How do I create and populate an array of strings.

Discussion in 'C Programming' started by Jeff Patterson, Oct 3, 2010.

  1. Trying to teach myself C and I'm stuck on this one. I tried:
    char *array_name[10];
    gets(array_name[0])
    But I get a runtime error. Apparently what I'm doing is creating an
    array of characters and trying to populate a single character element
    in that array. How do I create and populate an array of strings.
    Thanks in advance.
     
    Jeff Patterson, Oct 3, 2010
    #1
    1. Advertising

  2. Jeff Patterson

    Ian Collins Guest

    On 10/ 3/10 01:19 PM, Jeff Patterson wrote:
    > Trying to teach myself C and I'm stuck on this one. I tried:
    > char *array_name[10];


    This gives you an array or uninitialised character pointers. In order
    to use this as an array of C strings, you have to allocate memory for
    each string. Once you have allocated the memory, you can populate the
    strings.

    #include <stdio.h>
    #include <stdlib.h>

    enum { numberOfStrings = 10, sizeOfString = 128 };

    int main()
    {
    char *array_name[numberOfStrings];

    for( int n = 0; n < numberOfStrings; ++n )
    {
    // Allocate memory for the string.
    //
    array_name[n] = malloc( sizeOfString );

    // Populate the string.
    //
    fgets( array_name[n], sizeOfString, stdin );
    }

    for( int n = 0; n < numberOfStrings; ++n )
    {
    puts( array_name[n] );

    // Free memory used for the string.
    //
    free( array_name[n] );
    }
    }

    Notice I used fgets rather than gets. Using gets may cause your toilet
    to explode.

    --
    Ian Collins
     
    Ian Collins, Oct 3, 2010
    #2
    1. Advertising

  3. Jeff Patterson

    Rich Webb Guest

    On Sat, 2 Oct 2010 17:19:28 -0700 (PDT), Jeff Patterson
    <> wrote:

    >Trying to teach myself C and I'm stuck on this one. I tried:
    >char *array_name[10];
    >gets(array_name[0])
    >But I get a runtime error. Apparently what I'm doing is creating an
    >array of characters and trying to populate a single character element
    >in that array. How do I create and populate an array of strings.
    >Thanks in advance.


    C doesn't really have strings, as such. Rather, you get arrays of
    characters and pointers to characters and then build up from there.

    If you use fixed-length strings, assuming you've defined LEN_STRING and
    NUM_STRINGS, you could have
    char array_of_strings[NUM_STRINGS][LEN_STRING];
    which gives you 0 to NUM_STRINGS - 1 locations for strings that are
    LEN_STRING - 1 long (don't forget the terminal '\0').

    You could then do
    fgets(array_of_strings[0], LEN_STRING, stdin);
    which has the nice property (that gets() does not have) of limiting how
    many characters get stuffed into the destination.

    Never use gets(). Just don't. If you're using a "Teach Yourself C" book
    that was written any time after, say, 1978 which recommends using
    gets(), throw it away.

    --
    Rich Webb Norfolk, VA
     
    Rich Webb, Oct 3, 2010
    #3
  4. Jeff Patterson

    Seebs Guest

    On 2010-10-03, Jeff Patterson <> wrote:
    > Trying to teach myself C and I'm stuck on this one. I tried:
    > char *array_name[10];
    > gets(array_name[0])
    > But I get a runtime error.


    Not surprising!

    > Apparently what I'm doing is creating an
    > array of characters and trying to populate a single character element
    > in that array.


    No, that's not it at all.

    You've created an array of pointers, and you're trying to populate the
    areas of memory they point to.

    Just one question... Where *DO* they point to? Did you arrange any
    storage for them to point to? Because if not, you can't really expect
    this to work.

    > How do I create and populate an array of strings.


    1. Don't use gets(). It's unsafe.
    2. Consider:

    char *array_name[10]
    char buffer[512];
    array_name[0] = &buffer[0];
    fgets(array_name[0], 512, stdin);

    When we declared 'buffer', we reserved 512 bytes of storage. Then we set
    the first of those ten pointers to point to the beginning of that buffer...

    -s
    --
    Copyright 2010, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
    I am not speaking for my employer, although they do rent some of my opinions.
     
    Seebs, Oct 3, 2010
    #4
  5. On Oct 2, 7:19 pm, Jeff Patterson <>
    wrote:
    > Trying to teach myself C and I'm stuck on this one. I tried:
    > char *array_name[10];
    > gets(array_name[0])
    > But I get a runtime error. Apparently what I'm doing is creating an
    > array of characters and trying to populate a single character element
    > in that array. How do I create and populate an array of strings.
    > Thanks in advance.


    Many implementations offer the (non-standard) strdup functions
    which greatly simplifies this task.

    536(1)03:12 AM:~ 0> make slurp && slurp
    cc -g -Wall slurp.c -o slurp
    slurp.c:4:1: warning: "_BSD_SOURCE" redefined
    In file included from /usr/include/stdio.h:28,
    from slurp.c:1:
    /usr/include/features.h:176:1: warning: this is the location of the
    previous definition
    #include <stdio.h>
    #include <stdlib.h>

    #define _BSD_SOURCE /*enable strdup*/
    #include <string.h>

    #define NBUF 1024

    char **slurp(FILE *f) {
    char buf[ NBUF ];
    char **sv;
    char **ptr;
    size_t nv;

    for ( sv = malloc( (nv=1) * sizeof *sv ), ptr = sv + (nv-1);
    fgets(buf, sizeof buf, f) != NULL;
    sv = realloc(sv, (++nv) * sizeof *sv), ptr = sv + (nv-1) )
    {
    *ptr = strdup(buf);
    }
    *ptr = NULL;

    return sv;
    }

    void print(FILE *f, char **sv) {
    while (*sv) fputs(*sv++, f);
    }

    int main() {
    FILE *f;
    char **lines;

    f = fopen("slurp.c","r");
    lines = slurp(f);
    print(stdout, lines);

    return 0;
    }
    537(1)03:13 AM:~ 0>
     
    luser- -droog, Oct 4, 2010
    #5
  6. Jeff Patterson

    riccardo Guest

    On 10/03/2010 02:19 AM, Jeff Patterson wrote:
    > Trying to teach myself C and I'm stuck on this one. I tried:

    ///Next line creates 10 uninitialized pointers to strings
    > char *array_name[10];

    ///Here are tring to access something unininitialized
    > gets(array_name[0])


    When creating the 10 pointers, those are not assigned any values, hence
    they could be pointing any memory location, possibly critical ones. The
    behavior you obtain trying to access these memory zones is in general
    dependent on the way your OS handle these errors and on the memory
    locations.
    A good but expencive way of programming for a beginner, is to set any
    uninitialized variable to NULL (zero), so in your case:

    #include <string.h>
    ...
    char *array_name[10];
    memset (array_name,0, 10);

    This prevents unpredictable behavior. When trying to access your vector,
    you will have a predictable behavior that tells you that your pointer
    isn't pointing any thing.
    If you feel brave enough you could let gdb handle this job for you;
    specific options exist that allow gdb to clear any new variable when
    created.
    Once you've done that, you start populating your array by allocating
    memory for the strings you want to store, with "malloc":

    //reserve 8 bytes (excluding the trailing zero) and
    //copy the pointer to these 8 bytes in array[2].
    array[2] = malloc(strlen("helloworld"));
    //copying the string
    memcpy(array[2], "helloworld", strlen("helloworld"));
    ...
    //memory deallocation (as it's not needed anymore at some point in the
    //program or at exit
    free(array[2]);
     
    riccardo, Oct 4, 2010
    #6
  7. riccardo <> writes:

    > On 10/03/2010 02:19 AM, Jeff Patterson wrote:
    >> Trying to teach myself C and I'm stuck on this one. I tried:

    > ///Next line creates 10 uninitialized pointers to strings
    >> char *array_name[10];

    > ///Here are tring to access something unininitialized
    >> gets(array_name[0])

    >
    > When creating the 10 pointers, those are not assigned any values,
    > hence they could be pointing any memory location, possibly critical
    > ones. The behavior you obtain trying to access these memory zones is
    > in general dependent on the way your OS handle these errors and on the
    > memory locations.
    > A good but expencive way of programming for a beginner, is to set any
    > uninitialized variable to NULL (zero), so in your case:
    >
    > #include <string.h>
    > ...
    > char *array_name[10];
    > memset (array_name,0, 10);


    I think you meant memset(array_name, 0, sizeof array_name); or some
    variation thereof. The size of the array is unlikely to be 10 (though
    it might be).

    It would be very nice if this worked, but the bit pattern of all zeros
    is not guaranteed to be a null pointer. You either need a loop or a
    sequence of memcpys that copy a known null pointer into the array.

    <snip>
    > //reserve 8 bytes (excluding the trailing zero) and
    > //copy the pointer to these 8 bytes in array[2].
    > array[2] = malloc(strlen("helloworld"));


    I count 11 bytes being reserved and that includes the trailing null.

    > //copying the string
    > memcpy(array[2], "helloworld", strlen("helloworld"));


    This does not copy the trailing null byte so array[2] is not guaranteed
    to be a string. strcpy(array[2], "helloworld"); is simpler in this case.

    <snip>
    --
    Ben.
     
    Ben Bacarisse, Oct 4, 2010
    #7
  8. Jeff Patterson

    Jorgen Grahn Guest

    On Mon, 2010-10-04, riccardo wrote:
    ....
    > A good but expencive way of programming for a beginner, is to set any
    > uninitialized variable to NULL (zero), so in your case:


    I kind of disagree: IMHO if you cannot immediately find a good value to
    initialize an auto variable with, it's better to just declare it and
    let your compiler tell you if there's a possibility that it gets used
    before it's initialized.

    Or not to declare it that early in the first place! C99 is over ten
    years old now.

    Arrays (like in this particular case) are a special case though.

    > #include <string.h>
    > ...
    > char *array_name[10];
    > memset (array_name,0, 10);


    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
     
    Jorgen Grahn, Oct 4, 2010
    #8
  9. Jeff Patterson

    Nick Guest

    Jeff Patterson <> writes:

    > Trying to teach myself C and I'm stuck on this one. I tried:
    > char *array_name[10];
    > gets(array_name[0])
    > But I get a runtime error. Apparently what I'm doing is creating an
    > array of characters and trying to populate a single character element
    > in that array. How do I create and populate an array of strings.
    > Thanks in advance.


    Just be aware that this is horribly painful in C. It's such a
    depressing experience that it could put you off the language.

    Eventually, we all end up with our own carefully crafted set of
    work-arounds for C's limited string handling.

    The language as a whole is well worth persevering with, but you may find
    trying something else to start with a lot less masochistic.
    --
    Online waterways route planner | http://canalplan.eu
    Plan trips, see photos, check facilities | http://canalplan.org.uk
     
    Nick, Oct 5, 2010
    #9
  10. On Mon, 04 Oct 2010 13:14:18 +0100, Ben Bacarisse
    <> wrote:

    > riccardo <> writes:


    > > A good but expencive way of programming for a beginner, is to set any
    > > uninitialized variable to NULL (zero), so in your case:
    > >
    > > #include <string.h>
    > > ...
    > > char *array_name[10];
    > > memset (array_name,0, 10);

    >
    > I think you meant memset(array_name, 0, sizeof array_name); or some
    > variation thereof. The size of the array is unlikely to be 10 (though
    > it might be).
    >

    Yes. Or 10 * sizeof (char*) or 10 * sizeof *array_name would also be
    (reliably) correct, though I think in this situation no better.

    > It would be very nice if this worked, but the bit pattern of all zeros
    > is not guaranteed to be a null pointer. You either need a loop or a
    > sequence of memcpys that copy a known null pointer into the array.
    >

    Well, on many implementations it does happen to work. It doesn't
    *always* work; for that you need to use a proper null pointer.

    And to pick nits while I'm here, you need either a loop or an unrolled
    sequence of either memcpy or assignment. You can reduce the sequence
    of memcpy's like (with some redundant pedagogy added):
    memcpy (ary+0, &nullptr, 1*itemsz);
    memcpy (ary+1, ary+0, 1*itemsz);
    memcpy (ary+2, ary+0, 2*itemsz);
    memcpy (ary+4, ary+0, 4*itemsz)
    memcpy (ary+8, ary+0, 2*itemsz);

    > <snip>
    > > //reserve 8 bytes (excluding the trailing zero) and
    > > //copy the pointer to these 8 bytes in array[2].
    > > array[2] = malloc(strlen("helloworld"));

    >
    > I count 11 bytes being reserved and that includes the trailing null.
    >

    'reserved' is ambiguous. The literal value (statically) occupies 11
    including null, but strlen is 10 and that's what's malloc'ed.

    > > //copying the string
    > > memcpy(array[2], "helloworld", strlen("helloworld"));

    >
    > This does not copy the trailing null byte so array[2] is not guaranteed
    > to be a string. strcpy(array[2], "helloworld"); is simpler in this case.
    >

    memcpy doesn't make it a string. strcpy does copy the null and would
    make it a string, but only if you had allocated space for the null.
     
    David Thompson, Oct 11, 2010
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ray Stevens
    Replies:
    1
    Views:
    367
    Curt_C [MVP]
    Dec 28, 2004
  2. Ben

    Strings, Strings and Damned Strings

    Ben, Jun 22, 2006, in forum: C Programming
    Replies:
    14
    Views:
    813
    Malcolm
    Jun 24, 2006
  3. Guest
    Replies:
    4
    Views:
    1,032
    Alexey Smirnov
    Jun 23, 2007
  4. Keith Beef
    Replies:
    0
    Views:
    284
    Keith Beef
    Oct 27, 2007
  5. Enjoy Life
    Replies:
    2
    Views:
    324
    Roland Hall
    Feb 23, 2005
Loading...

Share This Page