How to dynamically allocate memory for char** in C

2019-04-14 14:00发布

问题:

How would I go about dynamically allocating memory to char** list in this function?

Basically the idea of this program is I have to read in a list of words from a file. I cannot assume max strings or max string length.

I have to do other stuff with the C-strings but that stuff I should be fine with.

Thanks!

void readFileAndReplace(int argc, char** argv)
{
    FILE *myFile;
    char** list;
    char c;
    int wordLine = 0, counter = 0, i;
    int maxNumberOfChars = 0, numberOfLines = 0, numberOfChars = 0;

    myFile = fopen(argv[1], "r");

    if(!myFile)
    {
        printf("No such file or directory\n");
        exit(EXIT_FAILURE);
    }

    while((c = fgetc(myFile)) !=EOF)
    {
        numberOfChars++;
        if(c == '\n')
        {
            if(maxNumberOfChars < numberOfChars)
                maxNumberOfChars += numberOfChars + 1;

            numberOfLines++;
        }
    }

    list = malloc(sizeof(char*)*numberOfLines);

    for(i = 0; i < wordLine ; i++)
        list[i] = malloc(sizeof(char)*maxNumberOfChars);


    while((c = fgetc(myFile)) != EOF)
    {
        if(c == '\n' && counter > 0)
        {
            list[wordLine][counter] = '\0';
            wordLine++;
            counter = 0;
        }
        else if(c != '\n')
        {
            list[wordLine][counter] = c;
            counter++;
        }
    }
}

回答1:

Do like this:

char** list; 

list = malloc(sizeof(char*)*number_of_row);
for(i=0;i<number_of_row; i++) 
  list[i] = malloc(sizeof(char)*number_of_col);  

Additionally, if you are allocating memory dynamically. you are to free it as work done:

for(i=0;i<number_of_row; i++) 
  free(list[i] );
free(list);  

EDIT

In you revised question:

 int wordLine = 0, counter = 0, i;    

wordLine and counter are 0

before this code:

list = malloc(sizeof(char*)*wordLine+1);
for(i = 0;i < wordLine ; i++)
   list[i] = malloc(sizeof(char)*counter);  

you have to assign value to wordLine and counter variable

Also memory allocation should be before the following loop(outside):

 while((c = fgetc(myFile)) != EOF){
  :
  :
 }

EDIT:

New your third version of question. You are reading file two times. So you need to fseek(), rewind() to first char before second loop starts.

try with:

fseek(fp, 0, SEEK_SET); // same as rewind()
rewind(fp);             // same as fseek(fp, 0, SEEK_SET)

also I have doubt in your logic to calculate numberOfLines and maxNumberOfChars. please check that also

EDIT

I think your calculation for maxNumberOfChars = 0, numberOfLines = 0 is wrong try like this:

maxNumberOfChars = 0, numberOfLines = 0, numberOfChars = 0;
while((c = fgetc(myFile)) !=EOF){
     if(c == '\n'){
         numberOfLines++; 
         if(maxNumberOfChars < numberOfChars)
             maxNumberOfChars = numberOfChars;
         numberOfChars=0
     }
     numberOfChars++;
}    

maxNumberOfChars is max number of chars in a line.

Also change code:

malloc(sizeof(char)*(maxNumberOfChars + 1));  


回答2:

If I were you, I'd map the file to private memory, using mmap, and then iterate over the file, storing starts of words in an array of char** that you can increase as you go with realloc, and replacing line breaks with 0.

That way, you have your words in memory as a continuous block, you don't have to care about file I/O, because you have the entire text file in memory as char*, and you don't have to malloc an array of arrays.

For information on the functions, see the respective man pages, or drop me a comment :)

EDIT: If you don't know mmap yet, have a look at this: http://www.jimscode.ca/index.php/component/content/article/13-c/45-c-simple-mmap-example

Most C programmers today still try to read files into memory using fopen and friends, but that's completely unnecessary and introduces additionel levels of complexity. (buffering, growing arrays, ...) and mmap is a nice alternative that moves all the nasty work down to the OS