简体   繁体   中英

Dynamic memory allocation for an array of pointers to char in C

I'm building a word counter program. To achieve this, I was thinking about saving the string the user inputted, and using strtok() to split the sentence with space as the delimiter. But first I want to allocate enough memory for each word. Let's say the sentence is "Hello World". I've already dynamically allocated memory for the string itself. Now I want to split Hello World into 2 strings, "Hello" and "World". My goal is to allocate enough memory so that there's not too much empty space but I also don't want to allocate too little space. Here is my code so far:

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

char *strmalloc(char **string);
char *user_input = NULL;
char *word_array[];

int main(void) {
    printf("Enter a sentence to find out the number of words: ");
    user_input = strmalloc(&user_input);

    return 0;
}

char *strmalloc(char **string) {
    char *tmp = NULL;
    size_t size = 0, index = 0;
    int ch;

    while ((ch = getchar()) != '\n' && ch != EOF) {
        if (size <= index) {
            size += 1;
            tmp = realloc(*string, size);
            if (!tmp) {
                free(*string);
                string = NULL;
                break;
            }
            *string = tmp;
        }
        (*string)[index++] = ch;
    }
    return *string;
}

How would I go about doing this? Should I do the splitting first or allocate the space required for the array first?

You can count words without splitting the sentence, here is an example:

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

// Change this to change the separator characters
static inline char isSeparator(char ch) { return isspace(ch) || ispunct(ch); }

char * jumpSeparator(char *string) {
    while(string[0] && isSeparator(string[0])) string++;
    return string;
}
    
char * findEndOfWord(char *string) {
    while (string[0] && !isSeparator(string[0])) string++;
    return string;
}

int countWords(char *string) {
    char * ptr = jumpSeparator(string);
    if (strlen(ptr) == 0) return 0;
    int count = 1;
    while((ptr = findEndOfWord(ptr)) && ptr[0]) {
        ptr = jumpSeparator(ptr);
        if (!ptr) break;
        count++;
    }
    return count;
}
  
int main() {
    char * sentence = "This    is,a function... to||count words";
    int count = countWords(sentence);
    printf("%d\n", count); //====> 7
}

EDIT: Reusing the same functions here is another example that allocates substrings dynamically:

int main() {
    char * sentence  = "This    is,a function... to||split words";
    int count        = countWords(sentence); 
    char * ptr       = sentence, *start, *end;
    char ** substrings = malloc(count * sizeof(char *));
    int i=0;
    while((ptr = jumpSeparator(ptr)) && ptr[0]) {
        start           = ptr;
        ptr             = findEndOfWord(ptr);
        end             = ptr;
        int len          = end-start;
        char * newString = malloc(len + 1);
        memcpy(newString, start, len);
        newString[len]   = 0;
        substrings[i++]  = newString;
    }
    // Prints the result
    for(int i=0; i<count; i++) printf("%s\n", substrings[i]);

    // Frees the allocated memory
    for(int i=0; i<count; i++) free(substrings[i]);
    free(substrings);
    return 0;
}

Output:

This
is
a
function
to
split
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