How do I create and populate an array of strings.

J

Jeff Patterson

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.
 
I

Ian Collins

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.
 
R

Rich Webb

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.
 
S

Seebs

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
 
L

luser- -droog

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>
 
R

riccardo

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

Ben Bacarisse

riccardo said:
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.

//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>
 
J

Jorgen Grahn

.
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
 
N

Nick

Jeff Patterson said:
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.
 
D

David Thompson

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);
//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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,114
Members
46,702
Latest member
VernitaGow

Latest Threads

Top