简体   繁体   中英

How to allocate memory for an array of strings of unknown length in C

I have an array, say, text, that contains strings read in by another function. The length of the strings is unknown and the amount of them is unknown as well. How should I try to allocate memory to an array of strings (and not to the strings themselves, which already exist as separate arrays)?

What I have set up right now seems to read the strings just fine, and seems to do the post-processing I want done correctly (I tried this with a static array). However, when I try to printf the elements of text, I get a segmentation fault. To be more precise, I get a segmentation fault when I try to print out specific elements of text, such as text[3] or text[5]. I assume this means that I'm allocating memory to text incorrectly and all the strings read are not saved to text correctly?

So far I've tried different approaches, such as allocating a set amount of some size_t=k , k*sizeof(char) at first, and then reallocating more memory (with realloc k*sizeof(char)) if cnt == (k-2) , where cnt is the index of **text.

I tried to search for this, but the only similar problem I found was with a set amount of strings of unknown length.

I'd like to figure out as much as I can on my own, and didn't post the actual code because of that. However, if none of this makes any sense, I'll post it.

EDIT: Here's the code

int main(void){
  char **text;
  size_t k=100;
  size_t cnt=1;
  int ch;
  size_t lng;

  text=malloc(k*sizeof(char));

  printf("Input:\n");

  while(1) {

    ch = getchar();
    if (ch == EOF) {
      text[cnt++]='\0';
        break;
    }

    if (cnt == k - 2) {
      k *= 2;
      text = realloc(text, (k * sizeof(char))); /* I guess at least this is incorrect?*/
    }

    text[cnt]=readInput(ch); /* read(ch) just reads the line*/
    lng=strlen(text[cnt]);
    printf("%d,%d\n",lng,cnt);
    cnt++;
  }

  text=realloc(text,cnt*sizeof(char));
  print(text); /*prints all the lines*/

  return 0;
}

The short answer is you can't directly allocate the memory unless you know how much to allocate.

However, there are various ways of determining how much you need to allocate.

There are two aspects to this. One is knowing how many strings you need to handle. There must be some defined way of knowing; either you're given a count, or there some specific pointer value (usually NULL) that tells you when you've reached the end.

To allocate the array of pointers to pointers, it is probably simplest to count the number of necessary pointers, and then allocate the space. Assuming a null terminated list:

size_t i;
for (i = 0; list[i] != NULL; i++)
    ;
char **space = malloc(i * sizeof(*space));
...error check allocation...

For each string, you can use strdup() ; you assume that the strings are well-formed and hence null terminated. Or you can write your own analogue of strdup() .

for (i = 0; list[i] != NULL; i++)
{
    space[i] = strdup(list[i]);
    ...error check allocation...
}

An alternative approach scans the list of pointers once, but uses malloc() and realloc() multiple times. This is probably slower overall.

If you can't reliably tell when the list of strings ends or when the strings themselves end, you are hosed. Completely and utterly hosed.

C don't have strings. It just has pointers to (conventionally null-terminated) sequence of characters, and call them strings.

So just allocate first an array of pointers:

 size_t nbelem= 10; /// number of elements
 char **arr = calloc(nbelem, sizeof(char*));

You really want calloc because you really want that array to be cleared, so each pointer there is NULL . Of course, you test that calloc succeeded:

 if (!arr) perror("calloc failed"), exit(EXIT_FAILURE);

At last, you fill some of the elements of the array:

 arr[0] = "hello";
 arr[1] = strdup("world");

(Don't forget to free the result of strdup and the result of calloc ).

You could grow your array with realloc (but I don't advise doing that, because when realloc fails you could have lost your data). You could simply grow it by allocating a bigger copy, copy it inside, and redefine the pointer, eg

 { size_t newnbelem = 3*nbelem/2+10;
   char**oldarr = arr;
   char**newarr = calloc(newnbelem, sizeof(char*));
   if (!newarr) perror("bigger calloc"), exit(EXIT_FAILURE);
   memcpy (newarr, oldarr, sizeof(char*)*nbelem);
   free (oldarr);
   arr = newarr;
 }

Don't forget to compile with gcc -Wall -g on Linux (improve your code till no warnings are given), and learn how to use the gdb debugger and the valgrind memory leak detector.

In c you can not allocate an array of string directly. You should stick with pointer to char array to use it as array of string. So use

char* strarr[length];

And to mentain the array of characters You may take the approach somewhat like this:


  1. Allocate a block of memory through a call to malloc()
  2. Keep track of the size of input
  3. When ever you need a increament in buffer size call realloc(ptr,size)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM