3

What's the way when i want to store string that i don't know the size.

I do like this:

#include <stdio.h>    
#include <conio.h>

int main () {
    char * str;
    str = (char *)malloc(sizeof(char) + 1);
    str[1] = '\0';
    int i = 0;
    int c = '\0';

    do {
        c = getche();
        if(c != '\r'){
            str[i] = c;
            str[i + 1] = '\0';
            i++;
            str = (char *)realloc(str, sizeof(char) + i + 2);
        }
    } while(c != '\r');

    printf("\n%s\n", str);

    free(str);
    return 0;
}

I find this page: Dynamically prompt for string without knowing string size

Is it correct? If it is, then:

Is there any better way?

Is there more efficient way?

13
  • 1
    conio.h is non-standard. Commented Oct 12, 2017 at 9:34
  • 1
    Please read and understand the question on why not to cast the return value of malloc() and family in C. Note also that sizeof (char) is one, by definition, since sizeof gives its results in units of char. Commented Oct 12, 2017 at 10:29
  • 1
    "Is it correct?" - it's probably better to determine that for yourself. Create a few test cases to exercise likely problems (e.g. empty input, very long input, etc). Once you're sure it functions according to your specification, you might want to ask for critique over at Code Review. Be sure to read A guide to Code Review for Stack Overflow users first, as some things are done differently over there! Commented Oct 12, 2017 at 10:32
  • 1
    "Is there any better way?" IMO, allowing a user to consume unlimited memory resources as this approach attempts makes for code that invites hackers. Better to have a sane limited upper bound on string input length. Commented Oct 12, 2017 at 14:50
  • 1
    for that do...while() loop, replace all that with a call to readline(). that function will allocate enough memory from the heap for the whole line, and return a pointer to the allocated area in the heap. (or NULL if the allocation fails) Commented Oct 13, 2017 at 4:42

5 Answers 5

3

Is it correct?

No

The main problem is the use of realloc. It is just wrong. When using realloc never directly assign to the pointer that points to the already allocated memory - always use a temporary to take the return value. Like:

char * temp;
temp = realloc(str, 1 + i + 2);
if (temp == NULL)
{
     // out of memory
     .. add error handling
}
str = temp;

The reason for this is that realloc may fail in which case it will return NULL. So if you assign directly to str and realloc fails, you have lost the pointer to the allocated memory (aka the string).

Besides that:

1) Don't cast malloc and realloc

2) sizeof(char) is always 1 - so you don't need to use it - just put 1

Is there any better way? Is there more efficient way?

Instead of reallocating by 1 in each loop - which is pretty expensive performance wise - it is in many cases better to (re)allocate a bigger chunk.

One strategy is to double the allocation whenever calling realloc. So if you have allocated 128 bytes the next allocation should be 2*128=256. Another strategy is to let it grow with some fixed size which is significantly bigger than 1 - for instance you could let it grow with 1024 each time.

Sign up to request clarification or add additional context in comments.

Comments

2

I suggest using a buffer to avoid repeated realloc calls. Create a buffer or arbitary size e.g. 1024 when it fills up you can realloc more space to your dynamically allocated buffer and memmove the buffer into it.

Comments

2

The key to answering this question is to clarify the term "without knowing the size".

We may not know what amount of data we're going to get, but we may know what we're going to do with it.

Let us consider the following use cases:

  • We have restrictions on the data we need, for example: a person's name, an address, the title of a book. I guess we are good with 1k or a maximum of 16k of space.

  • We obtain a continuous flow of data, for example: some sensor or other equipment sends us data every second. In this case, we could process the data in chunks.

Answer:

  • We need to make an educated guess about the size we intend to process and allocate space accordingly.
  • We have to process data on the fly and we need to release the space that is no longer required.

Note: It is important to note, that we can't allocate unlimited size of memory. On some point we have to implement error handling and/or we need to store the data on 'disk' or somewhere else.

Note II: In case a more memory efficient solution is needed, using realloc is not recommended as it can duplicate the allocated size (if the system cannot simply increase the allocated space, it first allocates a new block of memory and copies the current contents) while running. Instead, an application-specific memory structure would be required. But I assume that is beyond the scope of the original question.

Comments

1

Is it correct?

Sort of.

We don't cast the result of malloc() in C.

Is there any better way?

That's primarily opinion-based.

Is there more efficient way?

With regards to time or space?

If you are asking about space, no.

If you are asking about time, yes.

You could dynamically allocate memory for an array with a small size, that would hold the string for a while. Then, when the array would not be able to hold the string any longer, you would reallocate that memory and double its size. And so on, until the whole string is read. When you are done, you could reallocate the memory again, and shrink the size to be the exact number you need for your string.

You see, calling realloc(), is costly in time, since it may have to move a whole memory block, since the memory must be contiguous, and there might not be any space left to perform that operation without moving the memory related to the string.


Note: Of course, a fixed sized array, statically created would be better in terms of time, but worse in terms of memory. Everything is a trade off, that's where you come into play and decide what best suits your application.

4 Comments

An array to store the allocated blocks or a linked storage structure can provide more space efficient solution, instead of reallocating all the time. But we may process the data instead of simply storing it!
Yes obviously @SchLx, but I doubt that this is OP's indent.
I just wanted to point out, the answer ''If you are asking about space, no." is not entirely true!
The most efficient way would be to statically allocate char str [FRICKEN_BIG_ARRAY]; and store the data there. Anyway, I think you accurately addressed all the reasons why this question shouldn't be answered in the first place.
0

How about this?

char *string_name;
asprintf(&string_name, "Hello World, my name is %s & I'm %d years old!", "James Bond", 27);
printf("string is %s", string_name);
free(string_name);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.