Pankaj-Talesara
Pankaj-Talesara

Reputation: 139

C - Array of pointers for strings - how to dynammically allocate memory

I am creating a program and in a learning phase of learning C. The given code is prototype for my code. What I want to do is dynammically increase length of array of pointers as I add new words.

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

#define MAX_LENGTH 20

int main(){
    char (*string)[0];
    char word[MAX_LENGTH + 1];

    string = malloc (sizeof(char));
    if(string == NULL)
        exit(EXIT_FAILURE);

    for (int i = 0; i < 5; i++){
        printf("Enter word: ");
        scanf("%20s", word);

        string = realloc (string, strlen(word) + sizeof(string));     
        if(string == NULL)
            exit(EXIT_FAILURE);

        strcpy(string[i], word);
        printf("%s\n", string[i]);
    }

    for (int i = 0; i < 5; i++){
        printf("%d: %s\n", i + 1, string[i]);
    }
}

But what is happening is same word is stored in every string. Here is output

Enter word: hello
hello
Enter word: this
this
Enter word: is
is
Enter word: the
the
Enter word: output
output
1: output
2: output
3: output
4: output
5: output

---NOT OUTPUT BUT WHAT I WAS EXPECTING---

Enter word: hello
hello
Enter word: this
this
Enter word: is
is
Enter word: the
the
Enter word: output
output
1: hello
2: this
3: is
4: the
5: output

I don't know what I am doing wrong. I searched for hour on google, stackoverflow and reddit and didn't find anything I can relate too. What am I doing wrong and how to fix it. The compiler is not giving any error, output is blank in vs code.

Upvotes: 0

Views: 1113

Answers (2)

einpoklum
einpoklum

Reputation: 132240

What I want to do is dynamically increase length of array of pointers as I add new words.

No, you don't. If you know in advance the number of words you intend to read, there is no sense in re-allocating the array of pointers again and again.

And while you may not be concerned with performance right now, you should bear in mind that dynamic memory allocation is quite an expensive operation.

Also, your choice of names is rather confusing: string suggests a single string, not multiple strings.

So, perhaps:

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

#define MAX_LENGTH 20
#define NUM_WORDS 5

int main(){
    char* words[NUM_WORDS];
    char word_scan_buffer[MAX_LENGTH + 1];

    for (int i = 0; i < NUM_WORDS; i++){
        printf("Enter word: ");
        scanf("%20s", word_scan_buffer);

        words[i] = malloc(strlen(word_scan_buffer)+1);
        if (words[i] == NULL) {
            fprintf(stderr, "Memory allocation for the %d'th string failed\n", i+1);
            exit(EXIT_FAILURE);
        }

        strcpy(string[i], word_scan_buffer);
        printf("%s\n", words[i]);
    }

    for (int i = 0; i < NUM_WORDS; i++){
        printf("%d: %s\n", i + 1, words[i]);
    }
}

This also avoids using the "magic number" 5 repeatedly, switching to a defined constant; and fails a little more gracefully, by printing an error message instead of just exiting.

Finally, it's not even that useful to malloc() space for each word, when you could just malloc((MAX_LENGTH+1)*NUM_WORDS) once, setting the pointers in words to point to within that allocated buffer to begin with. See also this C FAQ question:

How can I dynamically allocate a multidimensional array?

which illustrates this option.

Upvotes: 1

niry
niry

Reputation: 3308

What I want to do is dynamically increase length of array of pointers as I add new words.

You'll need to realloc() the array of pointers ("string") and malloc() for each word ("string[i]").

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

#define MAX_LENGTH 20

int main(){
    char **string = NULL;
    char word[MAX_LENGTH + 1];

    for (int i = 0; i < 5; i++){
        printf("Enter word: ");
        scanf("%20s", word);

        string = realloc(string, (i + 1) * sizeof(char *));
        if (string == NULL)
            exit(EXIT_FAILURE);

        string[i] = malloc(strlen(word)+1);
        if(string[i] == NULL)
            exit(EXIT_FAILURE);

        strcpy(string[i], word);
        printf("%s\n", string[i]);
    }

    for (int i = 0; i < 5; i++){
        printf("%d: %s\n", i + 1, string[i]);
    }
}

However, if you know the number of words you intend to ask, it would be better to simplify and not dynamically allocate and resize the buffer. The code would be simpler and the performance if much better.

If performance is a consideration and the number of words is unknown, I would recommend reallocating every 512 words (assuming most common 64bit/4kB block size architecture), and preallocating much larger chunk of memory to split into words yourself, as keep calling malloc() for every word will be a major performance hit.

You should also consider different, less confusing variable names. string is not a great name for a pointer to a pointer.

Upvotes: 2

Related Questions