How to dynamically allocate memory space for a string and get that string from user?

CStringMemory ManagementMallocDynamic

C Problem Overview


I want to read input from user using C program. I don't want to use array like,

char names[50];

because if the user gives string of length 10, then the remaining spaces are wasted.

If I use character pointer like,

char *names;

then I need to allocate memory for that in such a way of,

names = (char *)malloc(20 * sizeof(char));

In this case also, there is a possibility of memory wastage.

So, what I need is to dynamically allocate memory for a string which is of exactly same as the length of the string.

Lets assume,

If the user input is "stackoverflow", then the memory allocated should be of 14 (i.e. Length of the string = 13 and 1 additional space for '\0').

How could I achieve this?

C Solutions


Solution 1 - C

Read one character at a time (using getc(stdin)) and grow the string (realloc) as you go.

Here's a function I wrote some time ago. Note it's intended only for text input.

char *getln()
{
    char *line = NULL, *tmp = NULL;
    size_t size = 0, index = 0;
    int ch = EOF;

    while (ch) {
        ch = getc(stdin);

        /* Check if we need to stop. */
        if (ch == EOF || ch == '\n')
            ch = 0;

        /* Check if we need to expand. */
        if (size <= index) {
            size += CHUNK;
            tmp = realloc(line, size);
            if (!tmp) {
                free(line);
                line = NULL;
                break;
            }
            line = tmp;
        }

        /* Actually store the thing. */
        line[index++] = ch;
    }

    return line;
}

Solution 2 - C

You could have an array that starts out with 10 elements. Read input character by character. If it goes over, realloc another 5 more. Not the best, but then you can free the other space later.

Solution 3 - C

If you ought to spare memory, read char by char and realloc each time. Performance will die, but you'll spare this 10 bytes.

Another good tradeoff is to read in a function (using a local variable) then copying. So the big buffer will be function scoped.

Solution 4 - C

You can also use a regular expression, for instance the following piece of code:

char *names
scanf("%m[^\n]", &names)

will get the whole line from stdin, allocating dynamically the amount of space that it takes. After that, of course, you have to free names.

Solution 5 - C

Below is the code for creating dynamic string :

void main()
{
  char *str, c;
  int i = 0, j = 1;

  str = (char*)malloc(sizeof(char));

  printf("Enter String : ");

  while (c != '\n') {
    // read the input from keyboard standard input
    c = getc(stdin);

    // re-allocate (resize) memory for character read to be stored
    str = (char*)realloc(str, j * sizeof(char));

    // store read character by making pointer point to c
    str[i] = c;
      
    i++;
    j++;
  }

  str[i] = '\0'; // at the end append null character to mark end of string

  printf("\nThe entered string is : %s", str);

  free(str); // important step the pointer declared must be made free
}

Solution 6 - C

Here's a snippet which I wrote which performs the same functionality.

This code is similar to the one written by [Kunal Wadhwa](https://stackoverflow.com/a/25974472/8311083 "His answer").

char *dynamicCharString()
{
    char *str, c;
    int i = 0;
    str = (char*)malloc(1*sizeof(char));

    while(c = getc(stdin),c!='\n')
    {
	  str[i] = c;
	  i++;
	  realloc(str,i*sizeof(char));
    }
    str[i] = '\0';
    return str;
}

Solution 7 - C

First, define a new function to read the input (according to the structure of your input) and store the string, which means the memory in stack used. Set the length of string to be enough for your input.

Second, use strlen to measure the exact used length of string stored before, and malloc to allocate memory in heap, whose length is defined by strlen. The code is shown below.

int strLength = strlen(strInStack);
if (strLength == 0) {
    printf("\"strInStack\" is empty.\n");
}
else {
    char *strInHeap = (char *)malloc((strLength+1) * sizeof(char));
    strcpy(strInHeap, strInStack);
}
return strInHeap;

Finally, copy the value of strInStack to strInHeap using strcpy, and return the pointer to strInHeap. The strInStack will be freed automatically because it only exits in this sub-function.

Solution 8 - C

This is a function snippet I wrote to scan the user input for a string and then store that string on an array of the same size as the user input. Note that I initialize j to the value of 2 to be able to store the '\0' character.

char* dynamicstring() {
    char *str = NULL;
    int i = 0, j = 2, c;
    str = (char*)malloc(sizeof(char));
    //error checking
    if (str == NULL) {
        printf("Error allocating memory\n");
        exit(EXIT_FAILURE);
    }
    
    while((c = getc(stdin)) && c != '\n')
    {
        str[i] = c;
        str = realloc(str,j*sizeof(char));
        //error checking
        if (str == NULL) {
            printf("Error allocating memory\n");
            free(str);
            exit(EXIT_FAILURE);
        }
        
        i++;
        j++;
    }
    str[i] = '\0';
    return str;
}

In main(), you can declare another char* variable to store the return value of dynamicstring() and then free that char* variable when you're done using it.

Solution 9 - C

char* load_string()
 {

char* string = (char*) malloc(sizeof(char));
*string = '\0';

int key;
int sizer = 2;

char sup[2] = {'\0'};

while( (key = getc(stdin)) != '\n')
{
    string = realloc(string,sizer * sizeof(char));
    sup[0] = (char) key;
    strcat(string,sup);
    sizer++

}
return string;

}

int main()
  {
char* str;
str = load_string();

return 0;
  }

Solution 10 - C

realloc is a pretty expensive action... here's my way of receiving a string, the realloc ratio is not 1:1 :

char* getAString()
{    
    //define two indexes, one for logical size, other for physical
    int logSize = 0, phySize = 1;  
    char *res, c;

    res = (char *)malloc(sizeof(char));

    //get a char from user, first time outside the loop
    c = getchar();
    
    //define the condition to stop receiving data
    while(c != '\n')
    {
        if(logSize == phySize)
        {
            phySize *= 2;
            res = (char *)realloc(res, sizeof(char) * phySize);
        }
        res[logSize++] = c;
        c = getchar();
    }
    //here we diminish string to actual logical size, plus one for \0
    res = (char *)realloc(res, sizeof(char *) * (logSize + 1));
    res[logSize] = '\0';
    return res;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDineshView Question on Stackoverflow
Solution 1 - CcnicutarView Answer on Stackoverflow
Solution 2 - CtekknolagiView Answer on Stackoverflow
Solution 3 - CBigMikeView Answer on Stackoverflow
Solution 4 - CJytugView Answer on Stackoverflow
Solution 5 - CKunal WadhwaView Answer on Stackoverflow
Solution 6 - CNiharGhtView Answer on Stackoverflow
Solution 7 - CEdwardView Answer on Stackoverflow
Solution 8 - CAndré FaelView Answer on Stackoverflow
Solution 9 - CShihanView Answer on Stackoverflow
Solution 10 - COmerView Answer on Stackoverflow