Thread: Append to strings

  1. #1
    Registered User
    Join Date
    Aug 2014
    Posts
    15

    Question Append to strings

    I am making a program that formats a string. I want to create a new 2 dimensional string that will have many other chars and strings in it beside the original string. Then I split the string up on the newlines and return it. What I need help on is adding different parts to the 2d string e.g. I need to add five _ as chars not string then I need to add different things. First I use sprintf () to add as much as possible. And then I do what to add the rest?

  2. #2
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    Could you please explain it with and example?

    i.e.
    Starting with... It is changed to...
    Fact - Beethoven wrote his first symphony in C

  3. #3
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by yuxuantim View Post
    I want to create a new 2 dimensional string that will have many other chars and strings in it beside the original string.
    That part of your description is as clear as mud, and your subsequent description is even less clear.

    There is no such thing as a 2 dimensional string.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  4. #4
    Registered User
    Join Date
    Aug 2014
    Posts
    15
    Ok I'm making a 2d array of chars ie
    Code:
    foo [x][y];
    I have in the function signature:
    Code:
    void func (char *string );
    I want to do this
    Code:
    foo[0]=string+"_";
    foo[0]=foo[0]+('A' * 7 );
    I know that is impossible. But do you understand?
    How can I add lots of things to a char array at different times?
    I know that multiplying a char doesn't work (except in perl).
    And I know adding strings together doesn't work (except in C++).
    And I know I cannot assign strings with an equal sign.

  5. #5
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    To put a string in an array strcpy() or strncpy() out of the header string.h

    To append: strcat() or strncat() out of string.h is what you are after. Make sure that the size of your arrays are large enough.
    Fact - Beethoven wrote his first symphony in C

  6. #6
    Registered User
    Join Date
    Aug 2014
    Posts
    15
    Well my main problem is putting ints and char in

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by yuxuantim
    I want to do this:
    Code:
    foo[0]=string+"_";
    foo[0]=foo[0]+('A' * 7 );
    I know that is impossible. But do you understand?
    How can I add lots of things to a char array at different times?
    I know that multiplying a char doesn't work (except in perl).
    And I know adding strings together doesn't work (except in C++).
    And I know I cannot assign strings with an equal sign.
    I think that you should put aside your 2D array of char that is an array of strings and first experiment on a 1D array of char that is used to store a single string. You obviously are unfamiliar with basic string manipulation; manipulating an array of strings just makes things more difficult to grasp.

    For example, suppose you have a string "abc" and wish to append "_" to it. You might write:
    Code:
    char x[5] = "abc";
    strcat(x, "_");
    Notice that I declared x as having 5 characters: 'a', 'b', 'c', '_' and '\0'.

    Suppose you have another string, also "abc" initially, and wish to append 'A' to it 7 times. You might write:
    Code:
    char y[11] = "abc";
    size_t y_length = strlen(y);
    size_t i;
    for (i = y_length; i < y_length + 7; ++i)
    {
        y[i] = 'A';
    }
    y[y_length + 7] = '\0';
    In this case I have chosen to manually write 'A' to the desired location in the array, terminating with a null character so that the result is a string. There are other ways by which one might do this.

    Quote Originally Posted by yuxuantim
    Well my main problem is putting ints and char in
    Perhaps you should look into the use of sprintf.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    Quote Originally Posted by yuxuantim View Post
    Ok I'm making a 2d array of chars ie
    Code:
    foo [x][y];
    I have in the function signature:
    Code:
    void func (char *string );
    I want to do this
    Code:
    foo[0]=string+"_";
    foo[0]=foo[0]+('A' * 7 );
    I know that is impossible. But do you understand?
    How can I add lots of things to a char array at different times?
    I know that multiplying a char doesn't work (except in perl).
    And I know adding strings together doesn't work (except in C++).
    And I know I cannot assign strings with an equal sign.
    Depending on your experience with the C language, what you are after may not be trivial. Perhaps you should consider using a string library (such as bstring or glib's string utility functions, for example).

    As already pointed out, the standard C string library provides functions such as strcat(), strncat(), sprintf(), snprintf(), etc for concatenating c-strings, but it's up to you to make sure that the destination string is large enough to hold the result.

    Your example comes from languages that handle dynamically the length of the strings for you. They also arm you with convenient syntactic sugar for manipulating them.

    The closest alternative in C, would be to either use a string library, or write your own (perhaps only with the functionality you need).

    As a primitive (and rather inefficient) example, the following sample program defines & uses two functions: s_append() and s_append_ntimes() for doing what you asked for, but they operate on dynamically allocated c-strings (instead of statically allocated ones).

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAX_STRINGS  10
    
    /* -------------------------------------------------
     * Append source c-string (src) to destination c-string (dst).
     * Return dst, or NULL on error.
     *
     * NOTES:
     *
     *   On success, dst may have been moved to a different location
     *   in memory (due to realloc).
     *
     *   On failure, dst remains unchanged (passing src as NULL
     *   or as an empty c-string, results in failure).
     * -------------------------------------------------
     */
    char *s_append( char **dst, const char *src )
    {
        char *test = NULL;
        size_t srclen = 0;
        size_t dstlen = 0;
    
        if ( NULL == dst || NULL == src || '\0' == *src ) {
            return NULL;
        }
    
        srclen = strlen( src );
        dstlen = NULL == *dst ? 0 : strlen( *dst );
    
        test = realloc( *dst, dstlen + srclen + 1 );
        if ( NULL == test ) {
            return NULL;
        }
        *dst = test;
    
        strcpy( &(*dst)[dstlen], src );
        return *dst;
    }
    
    /* -------------------------------------------------
     * Similar to function: s_append(), but this one
     * appends ntimes copies of the source c-string
     * to the destination c-string.
     * -------------------------------------------------
     */
    char *s_append_ntimes( char **dst, const char *src, int ntimes )
    {
        char *test = NULL;
        size_t srclen = 0;
        size_t dstlen = 0;
    
        if ( NULL == dst || NULL == src || '\0' == *src || ntimes < 1 ) {
            return NULL;
        }
    
        srclen = strlen( src );
        dstlen = NULL == *dst ? 0 : strlen( *dst );
    
        test = realloc( *dst, 1 + dstlen + (ntimes * srclen) );
        if ( NULL == test ) {
            return NULL;
        }
        *dst = test;
    
        while ( ntimes-- > 0 ) {
            strcat( &(*dst)[dstlen], src );
            dstlen += srclen;
        }
    
        return *dst;
    }
    
    /* -------------------------------------------------
     * Free the c-strings of the specified array of c-strings
     * and return NULL.
     * -------------------------------------------------
     */
    char *sarr_free_strings( char *sarr[MAX_STRINGS] )
    {
        int i;
        for (i=0; i < MAX_STRINGS; i++) {
            if ( NULL != sarr[i] ) {
                free( sarr[i] ); 
            }
        }
        return NULL;
    }
    
    
    /* -------------------------------------------------
     *
     * -------------------------------------------------
     */
    int main( void )
    {
        const char *string = "I'm a string";
        char *sarr[ MAX_STRINGS ] = { NULL };  /* array of c-strings */
    
        s_append( &sarr[0], string );
        s_append( &sarr[0], "_" );
        s_append_ntimes( &sarr[0], "A", 7 );
        puts( sarr[0] );
    
        sarr_free_strings( sarr );
    
        return 0;
    }
    
    /* Output:
    I'm a string_AAAAAAA
    */
    Last edited by migf1; 08-16-2014 at 03:04 AM.
    "Talk is cheap, show me the code" - Linus Torvalds

  9. #9
    Registered User zub's Avatar
    Join Date
    May 2014
    Location
    Russia
    Posts
    104
    I advise you to look at the source code of the unit-testing framework CuTest. About half of it takes a framework for working with strings of arbitrary length (CuString). It is a very convenient solution of your problem.

    SourceForge.net Repository - [cutest] Contents of /cutest/CuTest.c
    Our goals are clear, tasks are defined! Let's work, comrades! -- Nikita Khrushchev

  10. #10
    Registered User
    Join Date
    Aug 2014
    Posts
    15
    migf1 OK I like your idea best. Any ideas to get me started on my own library. I will make use of your code For the time being I did an easy fix. I made a holder string and sprintf a char or int into it then I strcat it onto my string. I now am wanting to separate a string on the spaces…

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by yuxuantim
    migf1 OK I like your idea best.
    I hope that you like it because of the good idea of creating/using a library, not because you were shown code that you think you can just take and use. You should develop the skills related to string manipulation as they will form a part of your problem solving skillset, even if in "real life" you end up using libraries or higher level languages for string manipulation.

    Quote Originally Posted by yuxuantim
    Any ideas to get me started on my own library.
    It is usually a good idea to check out the competition before starting work on a product. Both migf1 and zub have linked to existing libraries that you might want to investigate before starting on your own.

    Quote Originally Posted by yuxuantim
    I now am wanting to separate a string on the spaces
    Read up on strtok.
    Last edited by laserlight; 08-16-2014 at 12:37 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    Registered User
    Join Date
    Aug 2014
    Posts
    15
    I don't know how to mark a thread as closed but I think that I got everything. BTW I am doing this to learn, not because I have to. So I am not just going to steal your code. I'm going to learn.

  13. #13
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by yuxuantim View Post
    BTW I am doing this to learn, not because I have to. So I am not just going to steal your code. I'm going to learn.
    Unfortunately, people before you have conflated the concepts of "I will learn" and "Give me code to steal".
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  14. #14
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    Quote Originally Posted by yuxuantim View Post
    migf1 OK I like your idea best. Any ideas to get me started on my own library. I will make use of your code For the time being I did an easy fix. I made a holder string and sprintf a char or int into it then I strcat it onto my string. I now am wanting to separate a string on the spaces…
    A couple of years ago I had started a simple string library which was mostly operating on statically allocated string (meaning that most of them expect the size of the strings as argument).

    Unfortunately I've never finished it. However, its documentation can be found online, here. After the description of each function you'll find a line like the following:

    Definition at line 117 of file s2.c.
    By clicking on the line number you can see the code of that particular function.

    It seems that functions like: s_cappend(), s_tokenize() / s_tokenize_safe() and/or s_strtok() / s_strtok_r() may be useful for what you are after. Feel free to "steal" their code if you think it will help you.

    On the other hand, functions like the ones I've posted previously in this thread, operate on dynamically allocated c-strings, where the end programmer does not have to deal with lengths at all.

    But the code I posted in the previous post is not optimal. For example, you can save lots of realloc()s (it is a costly function) if you define a String data-type, which along the c-string data it will also hold the size of the c-string. During construction you can allocate it to a predefined number of bytes, and you will double it only when the String needs to grow beyond that.

    For example, for the s_append() function, you wouldn't have to realloc the destination string if 1 + strlen(dst) + strlen(src) was less that the currently (pre)allocated size of dst.

    This kind of low-level housekeeping may become quite tedious and error-prone (especially if you are not familiar with the language).

    That's why using an already tested string library, like the ones we've already pointed out in the thread, can save you lots of griff and frustration

    That being said, trying to write your own simple string library (for either static or dynamic strings, or even both), will certainly help you familiarize yourself with the language. It will be a nice learning experience, imo.

    You may start by improving the efficiency of the functions s_append() and s_append_ntimes() as described above.

    Writing a tokenizer using strtok() is not that difficult either (you may want to have a look at the code of the functions s_stokenize() / s_tokenize_safe() to get some ideas... or even better, look at the code of well established string-libraries, like the ones we have already suggested).

    Regarding sprintf(), if you like dynamically allocated strings better, glib provides three relative functions: g_strdup_printf(), g_strdup_vprintf() and g_vasprintf()

    I haven't looked at GLib's code, but I guess a simple implementation of the former two, could be something along the following lines:

    Code:
    /* --------------------------------------------------------------
     * char *s_dup_vprintf():
     *
     * This function is a wrapper to ISO C99's vsnprintf(). It creates
     * dynamically the buffer needed to hold the printed output, and if
     * it succeeds it returns a pointer to it. On error, it returns NULL.
     *
     * NOTES:
     *   1. vargs MUST have been already initialized in the caller
     *      (by the va_start macro, and possibly subsequent va_arg
     *      calls).
     *   2. The returned buffer, if non-NULL, MUST be freed in the
     *      calling environment
     * --------------------------------------------------------------
     */
    char *s_dup_vprintf( const char *fmt, va_list vargs )
    {
        int   nchars = 0;
        char  *buf = NULL;
        size_t bufsz = BUFSIZ;
    
        /* make buf to hold the text and pass it to vsnprintf */
        if ( NULL == (buf = calloc(1, bufsz)) ) {
            fprintf( stderr, "%s: calloc failed!\n", __func__ );
            goto ret_failure;
        }
        nchars = vsnprintf( buf, bufsz, fmt, vargs );
        if ( nchars < 0 ) {
            fprintf( stderr, "%s: vsnprintf failed!\n", __func__ );
            goto ret_failure;
        }
    
        /* Was buf too small to hold the text?
         * Reallocate 1+nchars bytes and re-apply.
         */
        if ( nchars >= (int)bufsz ) {
            char *try = NULL;
            bufsz = 1 + nchars;   /* for the NUL byte */
            try = realloc( buf, bufsz );
            if ( NULL == try ) {
                fprintf( stderr, "%s: realloc failed!\n", __func__ );
                goto ret_failure;
            }
            buf = try;
    
            nchars = vsnprintf( buf, bufsz, fmt, vargs );
            if ( nchars < 0 ) {
                fprintf( stderr, "%s: 2nd vsnprintf failed!\n", __func__ );
                goto ret_failure;
            }
        }
    
        return buf;
    
    ret_failure:
        if ( buf ) {
            free( buf );
        }
        return NULL;
    }
    
    /* --------------------------------------------------------------
     * char *s_dup_printf():
     *
     * This function is similar to ISO C99's snprintf() but it creates
     * dynamically the string needed to hold the print-out. It returns
     * the string, or NULL on error.
     * --------------------------------------------------------------
     */
    char *s_dup_printf( const char *fmt, ... )
    {
        char  *txtout = NULL;
        va_list vargs;
    
        va_start( vargs, fmt );
        txtout = s_dup_vprintf( fmt, vargs );
        va_end( vargs );
    
        return txtout;
    }
    So you can, for example...
    Code:
    ...
    int n = 10;
    char *temp = NULL;
    s_append(
        &sarr[0],
        temp = s_dup_printf( "%d", n )
        );
    free(temp);
    ...
    without worrying for the length of temp.
    Last edited by migf1; 08-16-2014 at 05:34 PM.
    "Talk is cheap, show me the code" - Linus Torvalds

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. append queue
    By stitches in forum C Programming
    Replies: 24
    Last Post: 09-11-2011, 06:31 AM
  2. append 2 strings into one variable
    By stormy in forum C Programming
    Replies: 3
    Last Post: 08-15-2005, 01:39 AM
  3. How to append bmp files to an EXE?
    By JoeDDDDYYY in forum C++ Programming
    Replies: 4
    Last Post: 01-28-2003, 02:24 PM
  4. append file?
    By Unregistered in forum C++ Programming
    Replies: 1
    Last Post: 09-27-2001, 08:37 AM

Tags for this Thread