Sayem Rahman
Sayem Rahman

Reputation: 141

a program using dynamic memory allocation to take a string of unknown size in c

I am making a program where user will input a string of unknown size,if the user input "END" then the program will terminate, otherwise, it will ask for another string and another As the size of the string is unknown, I used dynamic memory allocation to take the string of unknown size Heres what I have tried

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

int main() 
{
    bool on = true;
    char *string;
    while(on)
    {
        string = malloc(sizeof(char));
        int i;
        for (i = 0;; i++)
        {
            int n;
            n = getchar();
            if (n == '\n')
            {
                break;
            }
            else
            {
                string = realloc(string, sizeof(char));
                string[i] = (char)n;
            }
        }
        string[i] = '\0';
        if (strcmp(string, "END") == 0)
        {
            on = false;
        }
        printf("Len: [%i],String = %s\n",i+1,string);
        free(string);
    }
    return 0;
}

but if i input a string of size more than 25 or so, the program crashes, it gives me this output

0 [main] get_the_line_dynamically 1056 cygwin_exception::open_stackdumpfile: Dumping stack trace to get_the_line_dynamically.exe.stackdump

but, what's wrong with this code??

Upvotes: 1

Views: 393

Answers (1)

Clifford
Clifford

Reputation: 93476

realloc() allocates the size you specify and when the size is increased it copies data from the original allocation to the new allocation, then returns the old data to the heap. It is not incremental the size you pass it is the absolute size, not the size increase.

As such you need :

string = realloc( string, i + 2 ) ;

However incrementing in single bytes is horribly inefficient, requiring an allocation, data copy, and free for every single byte. The normal process is to increment the capacity in larger chunks, and increase the allocation only then the current capacity is exceeded. So you might have:

#define STRING_CAPACITY_INCREMENT 32
size_t string_capacity = STRING_CAPACITY_INCREMENT ;
char* string = malloc( string_capacity ) ;

Then:

// If insufficient capacity for new character plus NUL...
if( i + 2 > string_capacity )
{
    string_capacity += STRING_CAPACITY_INCREMENT ;
    string = realloc(string, string_capacity );
}
string[i] = (char)n;

That will improve time performance, but in case you are concerned about memory usage, bear in mind that memory allocations are 8 byte aligned, so single byte increments save nothing compared with a capacity increment of 8 for example. Also for that reason the increment should be a multiple of 8 too.

In some cases you might chose an exponential capacity increase such as doubling: 8, 16, 32, 64 etc. to some reasonable limit whereafter it becomes linear. That may be better in terms of balancing performance and memory usage if you have a lot of small strings and just a few long ones.

Upvotes: 5

Related Questions