简体   繁体   中英

Allocating space for a 2D string array before the text file is read

I'm reading from a large text file which contains a string followed by a newline. I'm using fgets to read each string and store them in a 2D string array as well as malloc to assign memory.

void read_file (char **dictionary, char * argv[])

{

FILE * file_name;
int i = 0, word_count = 0, c;

    file_name = fopen(argv[0], "r");
    if (file_name == NULL)
        {
            printf("Cannot open file");
        }
    while (fgets(dictionary[i], MAX_WORD_LENGTH, file_name))
        {
            dictionary[i][strlen(dictionary[i]) - 1] = '\0';
            word_count++;
            i++;
        }
    printf("\n%d words scanned in from: %s\n", word_count, argv[0]);
    fclose(file_name);
}

char ** AllocateDictionaryMemory (void)

{

int i;

char **p = malloc(MAX_WORDS * sizeof(*p));

        for (i = 0; i < MAX_WORDS; i++)
        {
            p[i] = malloc(MAX_WORD_LENGTH + 1);
        }
        if (p == NULL)
        {
            printf("Failed to allocate 2D string array space\n.");
        }

return p;

This uses a fixed value of MAX_WORD_LENGTH (10). However I'm now wanting to do it with with a non-fixed sized of words which is decided by finding the longest word in the text file it is given. I have a function to find the longest word in the dictionary as well. The problem is the malloc function needs max word length given to it, and the read_file function needs a dictionary array to read into - both of which happen before I can run the find longest word function.

I guess the question is - how can I find the longest word in the text file before I malloc space for the dictionary, and before the actual text file is read into the dictionary.

I know I could just set max_word_length to be something ridiculously huge but that kind of defeats the point - I want the size of the space to be decided once it has found the max word length.

read file --> find longest word --> malloc space big enough for the longest word --> read file into new space is the aim.

The following function goes through the file to count the length of all words and returns the length of the longest word.

int findLongestWord(FILE *fin)
{
    int c, i=0, longest= 0
    while ((c=fgetc(fin))!=EOF)
    {
        if (isspace(c)) {
            if (i>longest) longest= i;
            i= 0;
        }
        else i++;
    }
    if (i>longest) longest= i;    // suppose last word was longest..
    return longest;
}

Don't forget to rewind the file before processing it again.

The file can be read and memory allocated at the same time. This allocates each pointer but could be modified to allocate a block of pointers for efficiency. Each pointer has just enough memory allocated for the length of the input.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char** readwords( FILE *pf, int *wordcount);

int main( int argc, char *argv[])
{
    FILE *wordfile = NULL;
    char **s = NULL;
    int wordsize = 0;
    int each = 0;

    if ( argc < 2)
    {
        printf ( "program needs a filename as in:\nprogram filename\n");
        return 1;
    }

    if ( ( wordfile = fopen(argv[1], "r")) == NULL)
    {
        printf("Cannot open file");
        return 2;
    }

    s = readwords( wordfile, &wordsize);
    fclose ( wordfile);

    if ( s == NULL)
    {
        printf ( "no words in array\n");
        return 0;
    }

    for ( each = 0; each < wordsize; each++)
    {
        printf ( "%s\n", s[each]);
    }

    while ( wordsize) {
        wordsize--;
        free ( s[wordsize]);
    }
    free ( s);

    return 0;
}

char** readwords( FILE *pf, int *count)
{
    char** words = NULL;//NULL so realloc will work on the first call
    char** temp = NULL;
    char input[200] = "";

    //read each line into fixed size array
    while ( fgets ( input, sizeof ( input), pf))
    {
        //remove trailing newline if present
        input[strcspn ( input, "\n")] = '\0';
        //increment count of words
        *count = *count + 1;
        //allocate another pointer
        if ( ( temp = realloc ( words, *count * sizeof ( char *))) == NULL)
        {
            //if realloc fails 'words' should still be valid
            printf ( "realloc failed\n");
            *count = *count - 1;
            return words;
        }
        words = temp;//assign temp back to words
        //allocate memory to the pointer
        if ( ( words[*count - 1] = malloc ( strlen ( input) + 1)) == NULL)
        {
            printf ( "malloc failed\n");
            *count = *count - 1;
            return words;
        }
        strcpy ( words[*count - 1], input);
    }
    return words;
}

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