0

I want to make a program that stores inputed words into a 2D array (it can be as many as you want) and once you input word 'end', program should get out of the while loop. If I for example input these:

word1
word2
longer-word
end

Then the output should be:

List of words are:
word1
word2
longer-word

But here's the problem, I obviously dont know how many words will user input ( I dynamically allocated 2d array 5*20, so max 5 words), so what's the "correct" way of dynamically allocating 2D array, do I have to somehow reallocate every time user input new word or what? I really have no idea how to do it.

Here's a code:

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

char** allocate(int n, int m) {
    char** arr = (char**)malloc(sizeof(char*) * n);

    for (int i = 0; i < n; i++)
        arr[i] = (char*)malloc(sizeof(char) * m);

    return arr;
}

void print(char** words, int n, int m) {
    printf("List of words: \n");
    for (int i = 0; i < n; i++) {
        printf("%s\n", words[i]);
    }
}
int main() {
    char** words = allocate(5,20);
    char input[20];
    int index = 0;

    while ( strcmp("end", input) ) {
        scanf(" %s", input);

        if (strcmp("end", input) != 0) {
            strcpy(words[index], input);
            index++;
        }
    }
    
    print(words, 5, 20);
    return 0;
}

And also I noticed that when you input two words( with space ) it outputs those 2 words separately, so how can i prevent this?

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
ig2jmu
  • 17
  • 5

2 Answers2

2

What you need to is guess a reasonable size and allocate that. As you allocate your words you need to check that your limit is not hit. If it will be hit, then you need to realloc your array with a bigger size. A common strategy is to double the size each time.

doron
  • 27,972
  • 12
  • 65
  • 103
  • How do I reallocate it? I am trying it but unsuccessfully. Whats wrong with these : words = (char**)realloc(words, sizeof(char*) * (n + 20)); – ig2jmu Jun 28 '21 at 12:58
1

the array in c/c++ cannot be have a variable so this problem cannot be solved like this, also you can think of this 2d array as 1d array of strings. this is the solution that i came up with:

#define _CRT_SECURE_NO_WARNINGS

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

#define MAX_WORD_SIZE 20

char **allocate(int n, int m) {
    char **arr = (char **) malloc(sizeof(char *) * n);

    for (int i = 0; i < n; i++)
        arr[i] = (char *) malloc(sizeof(char) * m);

    return arr;
}

/**
 * first we will check if the count + 1 equal the size and if true we will create new array with a size
 * of size*2 and then move all the words to the new array, if it does not equal then we will copy the new word to the
 * array, also the array is passed by pointer so any change on this array in this scope it will change in the main.
 * @param words the words array that has all the words
 * @param newWord the new word to be inserted
 * @param index the index to insert the nwe word
 * @param size the size of the current array
 * @param wordSize the word size the second dimension in the array
 * @return will return a 2d array.
 */
char** addNewWord(char **words, char *newWord, int index, int *size, int wordSize) {

    if (index == *size) {
        int newSize = *size * 2;
        char **newArray = allocate(newSize, wordSize);
        for (int i = 0; i < *size; i++) {
            strcpy(newArray[i], words[i]);
        }
        strcpy(newArray[index], newWord);
        *size = newSize;
        return newArray;
    }
    strcpy(words[index], newWord);
    return words;
}

void print(char **words, int n) {
    printf("List of words: \n");
    for (int i = 0; i < n; i++) {
        printf("%s\n", words[i]);
    }
}

int main() {
    int size = 5;
    char **words = allocate(size, MAX_WORD_SIZE);
    char input[MAX_WORD_SIZE];
    int index = 0;

    while (1) {
        fgets(input, MAX_WORD_SIZE, stdin);
        input[strcspn(input,"\n")] = 0;
        if (strcmp("end", input) != 0) {
            words = addNewWord(words, input, index, &size, MAX_WORD_SIZE);
            index++;
        } else {
            break;
        }
    }
    print(words, index);
    return 0;
}

the way i did it is i have created a new function that is used to add the new word and if the index is equal the size of the array i have created a new array and copied the content of the first one to the second and this function will return the words array either the same array or the new one, also i have passed the size variable using pointer so i can change it in the function and this change will also change in the main.

--EDIT : i have changed the print from print(words,size) to print(words,index)

--EDIT 2: changed scanf() to fgets as it is much safer, thanks for chux - Reinstate Monica on the note, here is why scanf is dangerous.

  • 1
    `scanf(" %s", input);` is as bad as [`gets()`](https://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used) – chux - Reinstate Monica Jun 28 '21 at 14:57
  • that code was not mine i just wrote the part of the dynamic array, i am more fluent in c++ so i do not know what is a good practice in the c language, i will try and edit the code to include fgets(), thanks for the note – Mohammed Ziad Jun 28 '21 at 20:23
  • C is a different language to C++. Don't cast the value returned by `malloc()`. (In C++ you should use `new` not `malloc()` so the need to cast the result should not arise.) – mlp Jun 28 '21 at 21:53