1

I use realloc() on a string to make its size/memory smaller,so that way i lose the byte that had the null character '\0' in the end.I go and put back the null character for the new smaller size of the string.

The way i know to check a string's size is funtcion strlen(),but strlen will stop when it spots null character.

So the question is did i actually free the space or is strlen just stopping on the null character that i mannualy set at the end.How can i check ?

Just curious,how do you see my post so fast ?

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

char * function ()
{
    int number;
    char *string;

    printf("Give number: ");
    scanf("%i",&number);

    string = (char *) calloc(256,sizeof(char));

    printf("Give string: ");
    scanf("%s",string);

    string = (char *) realloc(string,number+1);//I make the string smaller

    string[number] = '\0';//I set the null at the end of the new size

    return string;
}

int main()
{
    char *string;

    string = function();

    printf("Size of string is: %i\n",strlen(string));//I check the size of string
    puts(string);

    return 0;
}
Jesepy
  • 37
  • 6
  • 2
    PSA: [Don't cast the result of `malloc`](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). – tadman Aug 13 '19 at 20:20
  • 1
    You check the result of `realloc`. If it succeed, then you can assume it have allocated whatever you asked it to allocate. If it is allocating more - it's not of your concern as you still should not use this memory. – Eugene Sh. Aug 13 '19 at 20:21
  • 2
    I'm not sure `realloc` is obligated to reallocate at all. You're just telling it that you'd like to, and it takes that under advisement. The only requirement is it gives you an allocation *at least* as much as you ask for. In some cases there may be granularity on the allocator level where going from, say, 63 bytes to 62 doesn't actually do anything. – tadman Aug 13 '19 at 20:22
  • @tadman Thanks,i will stop casting,i did because our teacher showed it like that – Jesepy Aug 13 '19 at 20:22
  • If you really want to know what's going on, your compiler may have an allocator debugging feature where it gives you details on each allocation or reallocation performed, plus a breakdown of the heap. This is compiler-specific, so check your compiler's docs. – tadman Aug 13 '19 at 20:28
  • @EugeneSh. I checked with a if ( *temp == NULL) wasnt true so i should be good then ? – Jesepy Aug 13 '19 at 20:28
  • @tadman i think visualstrudio had something like that,im currently on codeblocks – Jesepy Aug 13 '19 at 20:29
  • 1
    if you have something like `temp = realloc(string....); if (temp) string = temp; else fail` then you should be fine – Eugene Sh. Aug 13 '19 at 20:31
  • @EugeneSh. Ye i did that,it went fine – Jesepy Aug 13 '19 at 20:32
  • 1
    @tadman The question you linked is "Do I cast the result of malloc", not "Don't cast the result of malloc". The discussion there lists pros and cons, and just because the answer in favor of "con" has some more votes doesn't make it the one and only truth. Casting malloc is perfectly ok and a matter of style. – Ctx Aug 13 '19 at 21:02
  • @Ctx The accepted answer with a bazillion upvotes of support is "No, you don't". – tadman Aug 13 '19 at 21:12
  • @tadman Well, it doesn't need a thorough analysis to see, that this is clearly an opinion and far from an objective truth/fact. Note, that I do not claim that you _should_ cast the result, but telling others that this is wrong is... well ... wrong ;) – Ctx Aug 13 '19 at 21:14
  • @Ctx You want to argue, take it up with the author of that answer as a comment. As far as I'm concerned, and as thousands of Stack Overflow users have whole-heartedly agreed, the best practice is to not do it. – tadman Aug 13 '19 at 21:16
  • @tadman This is "primarily opinion based" and doesn't really have a place here. codereview.stackexchange.com might be a better place for that discussion. You claim here, that one should _not_ cast the result of `malloc()` and I have the desire to set straight, that it is neither wrong, nor "bad practice", regardless what a handful users claim. – Ctx Aug 13 '19 at 21:17

2 Answers2

2

You can't "double-check" realloc if that's your question

The standard defines the behavior of realloc, if it failed to provide the number of consecutive bytes that you ask for it will return NULL.

Now, how many bytes does realloc actually use? The internals of memory management functions are implementation defined, but realistically you're using some multiple of the page size, which is usually 4KiB. The tricky part is you don't know where in the page realloc put you, so you can't rely on that.

Ask for the amount of bytes you need and you won't go wrong. Don't assume memory management functions are providing more than you ask for, and the standard provides the guarantee that you have at least what you need.

nickelpro
  • 2,537
  • 1
  • 19
  • 25
  • 1
    Well. [To an extent](https://stackoverflow.com/questions/16674370/why-does-malloc-or-new-never-return-null)... – Eugene Sh. Aug 13 '19 at 20:37
  • @EugeneSh. I see. – Jesepy Aug 13 '19 at 20:51
  • 1
    *realistically you're using some multiple of the page size, which is usually 4KiB* Each block is unlikely to use a full page internally. Handing out 4 KB blocks for 8-byte allocations is extremely wasteful. There's usually a management layer between `malloc()` *et al* and the full pages given to a process by the kernel via `brk()`/`sbrk()` and/or `mmap()`. glibc, for example can use `brk()`/`sbrk()` for smaller requests, and `mmap()` directly for larger requests. Memory management libraries for high-performance multithreaded programs can get really complex. – Andrew Henle Aug 13 '19 at 22:04
  • 1
    @AndrewHenle That's what I meant by "you don't know where in the page `realloc` put you, so you can't rely on that." Obviously malloc isn't going to call mmap for every single allocation, and malloc has its own overhead as well. I'm just pointing out if you're monitoring program memory usage, it'll be in 4K blocks. `brk()` can move the break around arbitrarily, but memory protection only has page-granularity so you wont segfault anywhere in the page `brk()` is located. All of that memory exclusively belongs to the one program, see: https://elixir.bootlin.com/linux/latest/source/mm/mmap.c#L224 – nickelpro Aug 14 '19 at 00:49
  • @nickelpro *Obviously malloc isn't going to call mmap for every single allocation ...* I was aiming my comment at inexperienced programmers and non-programmers who might run across this question sometime in the future. Sorry if I didn't make that clear. – Andrew Henle Aug 14 '19 at 10:11
1

There are multiple issues to consider here:

  • realloc() returns the address of a block with at least the size requested if it succeeds, otherwise it returns a null pointer. Storing this return value directly into the passed pointer would overwrite this pointer with a null pointer if the call fails, making it impossible to use the original pointer, even just to free it.

  • scanf() should be passed the maximum number of bytes to read into the array, namely 255 in your example.

  • you should test the return value of scanf() to detect invalid input and avoid undefined behavior using unset variables in case of such failures.

  • you should test if number is positive. passing a negative value to realloc() will request an insanely large amount of memory causing the call to fail.

  • if you know the maximum string length, you can just allocate the correct size before reading the string.

  • regarding your question: if the number is less than 256 and you read a word longer than number bytes, setting string[number] = '\0'; is necessary to truncate the string because realloc() just shortened the array to number+1 bytes, potentially moving the contents, but preserved the byte at offset number.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • if i dont know the max size of string, my only option is to put a big size,my 256 and realloc() or is there a way to realloc the moment i get the string from user ? – Jesepy Aug 13 '19 at 20:42
  • 1
    @Jesepy: there is a non portable way to get `scanf()` to allocate the array on some systems with `scanf("%ms", &string)`: it will allocate (and reallocate) an array of the proper size and store its address into the pointer `string`. This extension is available on systems that use the GNU C library and may become standard some day. – chqrlie Aug 13 '19 at 20:49
  • 1
    @EugeneSh.: good point, but `readline()` reads a line of input whereas `scanf("%ms"), &p)` reads a single word. – chqrlie Aug 13 '19 at 20:52
  • Didnt know about %ms ill try it(is there a catch to it ?).Eugene what is readline ?I googled it didnt find much,and it kind of seemed out of my league for now,is there a post about it ?. – Jesepy Aug 13 '19 at 20:58
  • @EugeneSh. There's so much stuff there heh,ill check it later thanks – Jesepy Aug 13 '19 at 21:14
  • @chqrlie At first i thought of upvoting everyone hah.But thought its bad,but then i thought that you will like it,but then i say Stackoverflow saying to upvote the ones that helped with the solution,but everyone helped so i dont know what to do(writing too much ? nah). – Jesepy Aug 13 '19 at 21:21
  • @Jesepy: the policy is to upvote useful answers. As the OP, this means helping with the solution, sometimes in indirect ways by pointing to related info or non obvious problems. You can upvote all answers if they fit this scheme. – chqrlie Aug 13 '19 at 21:27
  • @Jesepy: yes, my rarest badge: awarded only 116 times in total. Let's clean up these comments, long discussions tend to get bumped to the chat rooms. – chqrlie Aug 13 '19 at 21:50