How do I create and populate an array of strings.

  • Follow


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.
0
Reply Jeff 10/3/2010 12:19:28 AM

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
0
Reply Ian 10/3/2010 12:45:10 AM


On Sat, 2 Oct 2010 17:19:28 -0700 (PDT), Jeff Patterson
<jeffrey.m.patterson@gmail.com> 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
0
Reply Rich 10/3/2010 1:42:59 AM

On 2010-10-03, Jeff Patterson <jeffrey.m.patterson@gmail.com> 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 / usenet-nospam@seebs.net
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.
0
Reply Seebs 10/3/2010 3:29:33 AM

On Oct 2, 7:19=A0pm, Jeff Patterson <jeffrey.m.patter...@gmail.com>
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 =3D malloc( (nv=3D1) * sizeof *sv ), ptr =3D sv + (nv-1);
        fgets(buf, sizeof buf, f) !=3D NULL;
        sv =3D realloc(sv, (++nv) * sizeof *sv), ptr =3D sv + (nv-1) )
    {
        *ptr =3D strdup(buf);
    }
    *ptr =3D NULL;

    return sv;
}

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

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

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

    return 0;
}
537(1)03:13 AM:~ 0>
0
Reply mijoryx (954) 10/4/2010 8:14:50 AM

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]);






0
Reply riccardo 10/4/2010 10:00:05 AM

riccardo <riccardo@yahoo.com> 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.
0
Reply Ben 10/4/2010 12:14:18 PM

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   .
0
Reply Jorgen 10/4/2010 10:20:23 PM

Jorgen Grahn wrote:
> 
> 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.

Some compilers can also tell you 
if an uninitialized auto variable
isn't being used at all.

-- 
pete
0
Reply pete 10/5/2010 2:01:50 AM

Jeff Patterson <jeffrey.m.patterson@gmail.com> 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
0
Reply 3-nospam (285) 10/5/2010 7:10:40 PM

On Mon, 04 Oct 2010 13:14:18 +0100, Ben Bacarisse
<ben.usenet@bsb.me.uk> wrote:

> riccardo <riccardo@yahoo.com> 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.

0
Reply David 10/11/2010 3:08:40 AM

10 Replies
202 Views

(page loaded in 0.192 seconds)


Reply: