Making an Array to Hold Arrays of Character Arrays in C
Asked Answered
I

5

15

My C is a little more than rusty at the moment, so I'm failing to create something I think should be pretty basic.

Allow me to refer to character arrays as strings for this post. It will make things clearer for both me and you.

What I have is an array that can hold 1 or more strings. For instance {"ab", "cd", "ef"}. I want to make another array to store multiple versions of the array of strings. So something like {{"ab", "cd", "ef"}, {"gh", "ij"}, {"kl"}}.

What I have right now is:

char *arrayOfStrings[50]; // a single array to hold multiple strings
char **arrayOfArraysOfStrings[10]; // array to hold multiple snapshots of arrayOfStrings

The array of strings changes over time and I'm using the array of arrays of strings to basically hold historical snapshots of arrayOfStrings. My problem comes when I need to access the snapshot array for data. This is the code I have to put stuff into the snapshot array:

arrayOfArraysOfStrings[input_index] = arrayOfStrings; // you can assume input_index is updated correctly, I've already checked that.

This appears to be incorrect since when I try to access and print out the contents of the snapshot array, it only prints out the information from the most recent arrayOfStrings. The idea I was going for with this was to store the address of where arrayOfChars is pointing in an entry of the snapshot array so I can access it later.

Right now, access to an entry in the snapshot array is accomplished like this:

arrayOfArraysOfChars[historicalIndex][indexOfTargetChar]

There are several questions I'm looking to answer:

  1. Is the method I outlined appropriate for what I'm trying to do or is there a flaw in my overall logic?
  2. What am I doing wrong with my current code and how do I fix it?
  3. Is there a better way to do this, and if so, how does initialization of the arrays, addition to the arrays, and reading from the arrays work?

--edit 4/18-- Part of the problem is that I'm setting pointers in arrayOfArraysOfStrings to point to the same thing that arrayOfStrings is pointing to. That's bad since arrayOfStrings gets edited. I need some way to duplicate a 2D array... Preferably by simply allocating a new block of memory for arrayOfStrings to point at.

Inculpable answered 18/4, 2013 at 19:50 Comment(0)
R
21

You have one-too-many pointers in both of your arrays.

char arrayOfChars[50]; // a single array of characters
char *arrayOfArraysOfChars[10]; // array to hold multiple single arrays of characters

Since the arrayOfChars is being used like a buffer (new data always goes there first), you'll need to save a copy of the string into the arrayOfArrays. The POSIX function strdup should help here.

Notice & and * are opposites, so &* and *& do absolutely nothing.

You could also, make the arrayOfArrays literally that.

char arrayOfChars[50]; // a single array of characters
char arrayOfArraysOfChars[10][50]; // array to hold multiple single arrays of characters

With this setup, you should use strcpy to copy the data into arrayOfArrays.


Having read your edit, I think you need to start real simple. And FWIW the variable names are the wrong kind of Hungarian.

For what I think you're trying to do, I'd start with just a single char array. This will be the main buffer, to hold strings that are being input and examined.

enum { BUFSZ = 50 };
char buf[BUFSZ + 1];

Then you can use it with fgets or whatever.

fgets(buf, BUFSZ, infile);

To save these up in an array, I'd use strdup for its automatic trimming. If the strings are going to be mostly 2 characters long, I don't want 48 extra bytes being used for each one. So, an array of char pointers (strings).

enum { STRVSZ = 40 };
char *strv[STRVSZ + 1];
int i;
i = 0;
strv[i] = strdup(buf);
strv[i+1] = NULL; // This makes it an "argv-style" NULL-terminated array of strings
++i; // i is now the index of the next element, and a count of elements already added

Each element of strv is a char pointer. But to preserve our sanity, we're trying to abstract away some of that distracting detail for a moment, and treat strings as a separate data type.

Now to create lists of these, we do the same thing again. But there's no strdup-type function to make a duplicate of an array of pointers, so we have to separate the allocation and copying.

enum { STRVVSZ = 20 };
char **strvv[STRVVSZ + 1];
int j;
j = 0;
strvv[j] = calloc(i+1, sizeof *strvv[j]); // assuming i is the count of elements 
memcpy(strvv[j], strv, i * sizeof *strvv[j]);
++j; // j is now the index of the next string-pointer array in the array-of-same,
     // and a count of elements already added.

Now, my names are just as silly as yours, but they're shorter!

Ranjiv answered 18/4, 2013 at 20:9 Comment(3)
This is very close to nabbing the issue, but did not quite get it. I do actually need an array that holds multiple single arrays of characters (I will refer to arrays of characters as strings), but I also need an array that holds multiple arrays of strings. Give me a moment to update the OP with clearer language.Inculpable
This is at least theoretically exactly what I needed :). I'm not sure why the memcpy doesn't seem to be working, but I'll post details in a separate question. As far as the scope of this question is concerned, this is an excellent answer.Inculpable
I've edited to add ++i; and ++j; and comments on the importance of those lines.Ranjiv
F
7

you should learn what an array means. an array is basically a set of integer or character or anything. when you are storing a character value in an array, define it as,

char array[] = {"somestringhere"};

now you want to store such arrays in an another array. it is simple:

char* array1[];

the array1 will store values, which are of char* type i.e. the address of character arrays. now you want to store these in other array,

char** array2[];

this is, array of [address of arrays] now, all you have to do is;

array1[0] = array; //same as: array1[0] = *array[0];
array2[0] = *array1[0];

Now you've everything you need. Hope you are clear, to the core. :)

Foetus answered 18/4, 2013 at 19:51 Comment(1)
This was also helpful in clearing up what I'm trying to do, thanks. Now just need to figure out a way to make the pointer change.Inculpable
S
5

This example was done with turbo c+ 1.01 dos and works in the 3.0 dos version also.

char * text[] = {
  "message1",
  "message2",
  "message3"
};
Segno answered 6/10, 2014 at 20:23 Comment(0)
D
3

Note that your examples show arrays of pointers. If you want arrays of arrays (multidimensional arrays) specify all the sizes in the array definition.

char sentences[500][42]; /* sentences is an array of 500 elements.
                         ** each element is itself an array
                         ** capable of holding strings up to length 41 */
Delora answered 18/4, 2013 at 20:28 Comment(1)
You might like to read section 6 of the comp.lang.c FAQ which explains much better than I ever could why arrays are not pointers and pointers are not arrays.Delora
S
1

if storing text in a .c or .h file having more than one line of text, equivalent to the idea of an array of char arrays. can do this:

char * text[] = {
  "message1",
  "message2",
  "message3"
};

can also use char *text[], char near *text[], char far *text[], char huge *text[]. has to have an asterisk or star character for a pointer.

a for loop can be used to display text:

char i; // int type can also be used
for (i = 0, i < 3; i++)
  printf("%s\n", text[i]);

other loops:

char i = 0;  // may not be zero when declared as "char i;" only
while (i < 3) {
  printf("%s\n", text[i]);
  i++;
 }

or

char i = 0;  // may not be zero when declared as "char i;" only
do {
 printf("%s\n", text[i]);
 i++;
} while (i < 3);
Segno answered 16/9, 2014 at 2:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.