Char array can hold more than expected - c

I tried to run this code in C and expected runtime error but actually it ran without errors. Can you tell me the reason of why this happens?
char str[10];
scanf("%s",str);
printf("%s",str);
As I initialized the size of array as 10, how can code prints string of more than 10 letters?

As soon as you read or write from an array outside of its bounds, you invoke undefined behavior.
Whenever this happens, the program may do anything it wants. It is even allowed to play you a birthday song although it's not your birthday, or to transfer money from your bank account. Or it may crash, or delete files, or just pretend nothing bad happened.
In your case, it did the latter, but it is in no way guaranteed.
To learn further details about this phenomenon, read something about exploiting buffer overflows, this is a large topic.

C doesn't perform any bounds checking on the array. This can lead to buffer overflows attack on your executable.
The bound checking should be done at the user end to make it anti-buffer overflow.
Instead of typing in magic numbers when taking input from fgets in an array, always use the sizeof(array) - 1 operator on the array to take in that much, -1 for leaving a space for '\0' character.

This is a good question. And the answer
is that it there is indeed a memory problem
The string is read and stored from the address of str
up until the length of the actual read string demands,
and it exceeds the place you allocated for it.
Now, it may be not crash immediately, or even ever for
short programs, but it's very likely that when you expand
the program, and define other variables, this string will
overrun them, creating weird bugs of all kinds, and it may
eventually also crash.
In short, this is a real error, but it's not uncommon to have
memory bugs like this one which do not affect at first, but
do create bugs or crash the program later.

Related

avoiding char buffer overflow more efficiently

i wrote a simple in/out program
whenever i run it and enter the input and exceed the char limit i get
*** stack smashing detected ***: terminated Aborted (core dumped)
i searched it up and found it was a gcc thing for safety,i heard it might lead to seg faults so i experimented turning it off with -fno-stack-protector and it ran normally if i exceeded the char limit
but what if i want to write the program if the input length is unknown, is there a safer way to do this? more efficient that increasing the value in char to an ridiculously large value?
the code:
#include <stdio.h>
int main()
{
char in[1];
printf("in: ");
scanf("%s\0", &in);
printf("\nout: %s\n", in);
}
P.s- im new to C, >2 days old so a simple explanation would be appreciated
char in[1]; can hold only the empty string (a single null terminating byte), which is impossible to use safely with scanf.
Also note that explicitly stating the null terminating byte in a string literal is superfluous, as they are implicitly null terminated.
but what if i want to write the program if the input length is unknown, is there a safer way to do this? more efficient that increasing the value in char to an ridiculously large value?
The counter-questions here are:
What do you consider inefficient?
What do you define as ridiculously large?
As I see it, you have two options:
Use dynamically allocated memory to read strings of an arbitrary size.
Set a realistic upper limit on the length of of input to expect.
An example of #1 can be seen in library functions like POSIX getline or getdelim. Its re-implementation can be as simple as as malloc (realloc), getchar, and a loop.
The use of #2 depends greatly on the context of your program, and what it is supposed to do. Perhaps you a reading a single line, and a smallish buffer will suffice. Maybe you are expecting a larger chunk of data, and need more memory. Only you can decide this for yourself.
In any case, its up to you to avoid undefined behavior by preventing overflows before they happen. It is already too late if one has occurred.
Use field-width specifiers when using %s:
char buf[512];
if (1 != scanf("%511s", buf))
/* read error */;
or use sane functions like fgets, which allow you to pass a buffer size as an argument.
stack smashing detected
i searched it up and found it was a gcc thing for safety
That's indeed gcc's way of spotting run-time bugs in your code by inserting so-called "stack canaries" to spot stack corruption/overflows. More errors detected is a good thing.
i heard it might lead to seg faults
No, bugs in your application lead to seg faults. If the compiler provides ways to detect them before the OS, that's a good thing. Dormant but severe bugs in your program is a bad thing. However, the OS would possibly detect the bug too and say "seg fault".
so i experimented turning it off with -fno-stack-protector and it ran normally if i exceeded the char limit
Basically you know that you are an inexperienced driver and afraid you might hit other cars. To solve, this you drive with your eyes closed instead, so you won't see those cars you could hit. That doesn't mean that they disappear.
char in[1]; can only hold 1 byte of data and if you read out of bounds of this array, you invoke undefined behavior, which will manifest itself as stack smashing or seg faults. Because you are trying to write to memory that doesn't belong to you. This is the bug, this is the problem. The correct solution is to allocate enough memory.
(You also have a bug scanf("%s\0", &in); -> scanf("%s\0", in);. The & isn't needed since in is an array and automatically "decays" into a pointer to its first element when you pass it to a function.)
One sensible way is to allocate 128 bytes or so, and then restrict the input so that it cannot be more than 128 bytes. The proper function to read strings with restricted input length is fgets. So you could either switch to fgets or you could accept that your beginner trial programs need not live up to production quality and just use scanf for now. (You can use scanf safely as shown in another answer, but IMO that's just more cumbersome than using fgets.)
Also I would strongly advise C beginners not to worry about if they allocate 10 bytes or 100 bytes. Learn programming by using a PC and then it won't matter. Optimizing memory consumption is an advanced topic which you will learn later on.

Comparison to NULL pointer in c

This is a code from a tutorial in which user enters the size of the string and string itself. The code should uses memory allocation to reproduce the same string. I have few doubts in the code-
Why is the *text pointer initialized to NULL at the beginning? Was this initialization useful in later part of the program or it is good practice to initialize to NULL.
Why is it comparing the pointer to NULL. Won't the address change once we allocate a string to the pointer? At the end of the string will pointer point to NULL (no address)?
What is the use of scanf(" ")?
After freeing *text pointer, it was again allocated to NULL. So did it effectively free up memory?
#include <stdio.h>
#include <stdlib.h>
int main()
{
int size;
char *text = NULL; //---------------------------------------------------------->1
printf("Enter limit of the text: \n");
scanf("%d", &size);
text = (char *) malloc(size * sizeof(char));
if (text != NULL) //---------------------------------------------------------->2
{
printf("Enter some text: \n");
scanf(" "); //---------------------------------------------------------->3
gets(text);
printf("Inputted text is: %s\n", text);
}
free(text);
text = NULL;//---------------------------------------------------------->4
return 0;
}
Why is the *text pointer initialized to NULL at the beginning?
To protect you from your own humanity, mainly. As the code evolves, it's often easy to forget to initialize the pointer in one or more branches of code and then you're dereferencing an uninitialized pointer - it is undefined behavior, and as such it's not guaranteed to crash. In worst case, if you don't use proper tools such as Valgrind (it'd point it out right away), you can spend hours or days finding such a problem because of how unpredictable it is, and because the behavior changes based on what else was on the stack before the call - so you might see a "bug" in a completely unreleated and perfectly not-buggy code.
Why is it comparing the pointer to NULL.
Because malloc can return a NULL and just because it returns it doesn't mean you can dereference it. The null pointer value is special: it means "hey, this pointer is not valid, don't use it for anything". So before you dereference anything returned from malloc, you have to check that it's not null. To do otherwise is undefined behavior, and modern compilers may do quite unexpected things to your code when such behavior is present. But before asking such a question I'd advise to always check what is the function you're wondering about actually designed to do. Google cppref malloc and the first hit is: https://en.cppreference.com/w/c/memory/malloc. There, under the heading of Return value, we read:
On failure, returns a null pointer.
That's why it's comparing the pointer to NULL!
What is the use of scanf(" ")?
That one is easy: you could have looked it up yourself. The C standard library is well documented: https://en.cppreference.com/w/c/io/fscanf
When you read it, the relevant part is:
format: pointer to a null-terminated character string specifying how to read the input.
The format string consists of [...]
whitespace characters: any single whitespace character in the format string consumes all available consecutive whitespace characters from the input (determined as if by calling isspace in a loop). Note that there is no difference between "\n", " ", "\t\t", or other whitespace in the format string.
And there's your answer: scanf(" ") will consume any whitespace characters in the input, until it reaches either EOF or the first non-whitespace character.
After freeing *text pointer, it was again allocated to NULL. So did it effectively free up memory?
No. First of all, the language used here is wrong: the pointer was assigned a value of NULL. Nothing was allocated! Pointer is like a postal address. You can replace it with the word "NOWHERE", and that's what NULL is. But putting something like "this person has no address" in your address book you have not "allocated" anything.
Yes - free did free the memory. Then you can set it to NULL because you're human, so that you won't forget so easily that the pointer's value is not valid anymore. It's in this case a "note to self". Humans tend to forget that a pointer is null and then will use it. Such use is undefined behavior (your program can do anything, for example erase your hard drive). So the text = NULL assignment has nothing to do with the machine. It has everything to do with you: humans are not perfect, and it's best to program defensively so that you give yourself less chances to introduce a bug as you change the code, or as you work under deadline pressure, etc.
Generally speaking, the NULL assignment at the end of main is not necessary in such a simple short program. But you have to recognize the fact that text cannot be dereferenced after it has been free-d.
Personally, I find it best to leverage the property of C language that gives variables lexical scope. Once the scope ends, the variable is not accessible, so you can't write a bug that would use text - it won't compile. This is called "correctness by design": you design the software in such a way that some bugs are impossible by construction, and if you code the bug then the code won't compile. That's a million times better than catching the bug at runtime, or worse - having to debug it, potentially in unrelated code (remember: undefined behavior is nasty - it often manifests as problems thousands of lines away from the source).
So here's how I'd rewrite it just to address this one issue (there are others still left there):
#include <stdio.h>
#include <stdlib.h>
void process_text(int size)
{
char *const text = malloc(size * sizeof(char));
if (!text) return;
printf("Enter some text: \n");
scanf(" ");
gets(text);
printf("Inputted text is: %s\n", text);
free(text);
}
int main()
{
int size;
printf("Enter limit of the text: \n");
scanf("%d", &size);
process_text(size);
}
The scope of text is limited to the block of process_text. You initialize it immediately at the point of declaration: that's always preferred. There's no need to set it to NULL first, since you assign the desired value right away. You check if maybe malloc has returned NULL (i.e. it failed to allocate memory), and if so you immediately return from the function. A NULL check is idiomatically written as if (pointer) /* do something if the pointer is non-null */ or as if (!pointer) /* do something if the pointer IS NULL */. It's less verbose that way, and anyone reading such code is supposed to know what it means if they have any sort of experience. Now you know too what such code means. It's not a big hurdle to be aware of this idiom. It's less typing and less distraction.
Generally speaking, code that returns early should be preferred to nested if blocks and unending levels of indentation. When there are multiple checks before a function can do its job, they often end up in nested if statements, making the function much harder to read.
There's a flip side to that: in C++ the code is supposed to leverage C++ (i.e. it's not just C compiled with a C++ compiler), and the resources that have to be released when returning from a function should be automatically released by the compiler generated code that invokes destructors. But in C no such automatic destructor calls are made. So if you return from a function early, you have to make sure that you've released any resources that were allocated earlier on. Sometimes the nested if statements help with that, so you shouldn't be blindly following some advice without understanding the context and assumptions the advice makes :)
Although it's truly a matter of preference - and I have C++ background where the code written as above is way more natural - in C probably it'd be better not to return early:
void process_text_alternative_version(int size)
{
char *text = malloc(size * sizeof(char));
if (text) {
printf("Enter some text: \n");
scanf(" ");
gets(text);
printf("Inputted text is: %s\n", text);
}
free(text);
}
The value of text is only used if it's not null, but we don't return from the function early. This ensures that in all cases will the memory block pointed to by text - if any - gets freed! This is very important: it's yet another way to write code that's correct by design, i.e. in a way that makes certain mistakes either impossible or much harder to commit. Written as above, you have no way of forgetting to free the memory (unless you add a return statement somewhere inside).
It must be said that even though some decisions made in the design of the C language library have been atrocious, the interface to free has been thoughtfully made in a way that makes the above code valid. free is explicitly allowed to be passed a null pointer. When you pass it a null pointer - e.g. when malloc above failed to allocate the memory - it will do nothing. That is: "freeing" a null pointer is a perfectly valid thing to do. It doesn't do anything, but it's not a bug. It enables writing code like above, where it's easy to see that in all cases text will be freed.
A VERY IMPORTANT COROLLARY: null pointer checks before free (in C) or delete (in C++) indicate that the author of the code doesn't have a clue about the most basic behavior of free and delete: it's usually an indicator that the code will be written as if it was a black magical art that no mere mortal understands. If the author doesn't understand it, that is. But we can and must do better: we can educate ourselves about what the functions/operators that we use do. It's documented. It costs no money to look that documentation up. People have spent long hours making sure the documentation is there for anyone so inclined to see. Ignoring it is IMHO the very definition of insanity. It's sheer irrationality on a wild rollercoaster ride. For the sane among us: all it takes is a google search that includes the word cppref somewhere. You'll get cppreference links up top, and that's a reliable resource - and collaboratively written, so you can fix any shortcomings you note, since it's a wiki. It's called "cpp"reference, but it really is two references in one: a C++ Reference as well as a C Reference.
Back to the code in question, though: someone could have written it as follows:
void process_text_alternative_version_not_recommended(int size)
{
char *text = malloc(size * sizeof(char));
if (text) {
printf("Enter some text: \n");
scanf(" ");
gets(text);
printf("Inputted text is: %s\n", text);
free(text);
}
}
It's just as valid, but such form defeats the purpose: it's not clear at a glance that text is always freed. You have to inspect the condition of the if block to convince yourself that indeed it will get freed. This code will be OK for a while, and then years later someone will change it to have a bit fancier if condition. And now you got yourself a memory leak, since in some cases malloc will succeed, but free won't be called. You're now hoping that some future programmer, working under pressure and stress (almost invariably!) will notice and catch the problem. Defensive programming means that we protect ourselves not only from bad inputs (whether errant or malicious), but also from our own inherent human fallibility. Thus it makes most sense in my opinion to use the first alternative version: it won't turn into a memory leak no matter how you modify the if condition. But beware: messing up the if condition may turn it into undefined behavior if the test becomes broken such that the body of if executes in spite of the pointer being null. It's not possible to completely protect ourselves from us, sometimes.
As far as constness is concerned, there are 4 ways of declaring the text pointer. I'll explain what they all mean:
char *text - a non-const pointer to non-const character(s): the pointer can be changed later to point to something else, and the characters it points to can be changed as well (or at least the compiler won't prevent you from doing it).
char *const text - a const pointer to non-const character(s) - the pointer itself cannot be changed past this point (the code won't compile if you try), but the characters will be allowed to be changed (the compiler won't complain but that doesn't mean that it's valid to do it - it's up to you the programmer to understand what the circumstances are).
const char *text - a non-const pointer to const character(s): the pointer can be changed later to point somewhere else, but the characters it points to cannot be changed using that pointer - if you try, the code won't compiler.
const char *const text - a const pointer to const character(s): the pointer cannot be changed after its definition, and it cannot be used to change the character(s) it points to - an attempt to do either will prevent the code from compiling.
We chose variant #2: the pointed-to characters can't be constant since gets will definitely be altering them. If you used the variant #4, the code wouldn't compile, since gets expects a pointer to non-const characters.
Choosing #2 we're less likely to mess it up, and we're explicit: this pointer here will remain the same for the duration of the rest of this function.
We also free the pointer immediately before leaving the function: there's no chance we'll inadvertently use it after it was freed, because there's literally nothing done after free.
This coding style protects you from your own humanity. Remember that a lot of software engineering has nothing whatsoever to do with machines. The machine doesn't care much about how comprehensible the code is: it will do what it's told - the code can be completely impenetrable to any human being. The machine doesn't care one bit. The only entitities that are affected - positively or negatively - by the design of the code are the human developers, maintainers, and users. Their humanity is an inseparable aspect of their being, and that implies that they are imperfect (as opposed to the machine which normally is completely dependable).
Finally, this code has a big problem - it again has to do with humans. Indeed you ask the user to enter the size limit for the text. But the assumption must be that humans - being humans - will invariably mess it up. And you'll be absolutely in the wrong if you blame them for messing it up: to err is human, and if you pretend otherwise then you're just an ostrich sticking your head in the sand and pretending there's no problem.
The user can easily make a mistake and enter text longer than the size they declared. That's undefined behavior: the program at this point can do anything, up to and including erasing your hard drive. Here it's not even a joke: in some circumstances it's possible to artificially create an input to this program that would cause the hard drive to indeed be wiped. You may think that it's a far-off possibility, but that's not the case. If you wrote this sort of a program on an Arduino, with an SD card attached, I could create input for both size and text that would cause the contents of the SD card to be zeroed - possibly even an input that can all be typed on a keyboard without use of special control characters. I'm 100% serious here.
Yes, typically this "undefined behavior means you'll format your hard drive" is said tongue-in-cheek, but that doesn't mean preclude it from being a true statement in the right circumstances (usually the more expensive the circumstances, the truer it becomes - such is life). Of course in most cases the user is not malicious - merely error-prone: they'll burn your house down because they were drunk, not because they tried to kill you - that's an awesome consolation I'm sure! But if you get a user that's an adversary - oh boy, they absolutely will leverage all such buffer overrun bugs to take over your system, and soon make you think hard about your choice of career. Maybe landscaping doesn't look all that bad in retrospect when the alternative is to face a massive lawsuit over loss of data (whether disclosure of data or a true loss when the data is wiped and lost).
To this effect, gets() is an absolutely forbidden sort of an interface: it's not possible to make it safe, that is: to make it work when faced with users that are either human, drunk and just error-prone, or worse - an adversary determined to create yet another "Data leak from Bobby Tables' Bank, Inc." headline in the newspaper.
In the second round of fixes, we need to get rid of the gets call: it's basically a big, absurdly bad mistake that the authors of the original C standard library have committed. I am not joking when I say that millions if not billions of dollars have been lost over decades because gets and similarly unsafe interfaces should never ever have been born, and because programmers have been unwittingly using them in spite of their inherently broken, dangerous and unsafe design. What's the problem: well, how on Earth can you tell gets to limit the length of input to actually fit in however much memory you have provided? Sadly, you can't. gets assumes that you-the-programmer have made no mistakes, and that wherever the input's coming from will fit into the space available. Ergo gets is totally utterly broken and any reasonable C coding standard will simply state "Calls to gets are not allowed".
Yes. Forget about gets. Forget about any examples you saw of people calling gets. They are all wrong. Every single one of them. I'm serious. All code using gets is broken, there's no qualification here. If you use gets, you're basically saying "Hey, I've got nothing to lose. If some big institution exposes millions of their users' data, I'm fine with getting sued and having to live under a bridge thereafter". I bet you'd be not so happy about getting sued by a million angry users, so that's where the tale of gets ends. From now on it doesn't exist, and if someone tell you about using gets, you need to look at them weird and tell them "WTF are you talking about? Have you lost your mind?!". That's the only proper response. It's that bad of a problem. No exaggeration here, I'm not trying to scare you.
As for what to do instead of gets? Of course it's a well solved problem. See this question to learn everything you should know about it!
In this function:
It is not needed at all as there is no danger that the automatic variable will be used not initialized in this function
This test checks if malloc was successful or not. If malloc fails it returns NULL
a bit weird way to skip blanks
This statement is not needed at all. The function terminates and variable stops to exists.
The conclusion: I would not rather recommend this kind of code to be used as an example when you learn programming. The authors C knowledge is IMO very limited
Whenever we declare a variable, it is a good practice to initialize it with some value. As you are declaring a dynamic array here, you are initializing it with NULL.
It is set to NULL so that it can be helpful to check if the text is valid or not. If somehow the malloc failed, the text will be still NULL. So you can check whether the malloc failed or not to allocate the memory. Try to put an invalid number for size like -1. You will see that the program won't prompt for the text input, as malloc failed and text is still NULL. I think this answer your query 1, 2, and 4 about why the text is being set to NULL and why it is checking whether the text is NULL or not.
For the 3rd query, After you get the input of size using scanf("%d", &size);, you are pressing Enter. If you don't use the scanf(" ") the pressed Enter will be taken as the end of gets(text) and text would be always empty. So to ignore the Enter pressed after scanf("%d", &size);, scanf(" ") is being used.

Size doesn't increase, yet it stores larger data. How is this possible?

I was trying this code in gcc6.3:
char a[2];
char b[]="Aditya";
strcpy(a,b);
printf("%s %lu\n",a,sizeof(a));
the output was:
aditya#aditya-Gateway-series:~/luc$ ./a
Aditya 2
How can variable a be still 2 bytes big and store an information of 7bytes?
In your code:
strcpy(a,b);
invokes undefined behaviour, as you're trying to access memory which is not valid. Don't rely on the outcome.
To elaborate, a has only storage to hold two chars, if you try to write (here, to copy) more than a single-char string (with the null-terminator), you'll overrrun the allocated memory, thereby venturing into invalid memory location.
The source buffer of strcpy(), b has more content that can be fit into the destination buffer a, thus the operation involves boundary overrun. It's the job of the programmer to ensure that the destination buffer has sufficient memory.
That said, regarding the size calculation - let me add, array size, once defined, cannot be changed. You can chose to fill up the contents of leave them unitialized / unused, but arrays, once defined, cannot be resized.
As Sourav Ghosh said, your usage of strcpy is incorrect and induces undefined behavior. What I think happens is that a is of size 2, b is ob size 7, and they happen to be placed next to each other in the memory, resulting in 9 bytes of continuous allocated memory. So after copy, a is still of size 2, and holds "Ad" - however printing it displays the whole string as the print continues until first end-of-string character. If you print b, I think you'll get "itya", as its adress is located 2 bytes next to a.
I hope this is clear enough and it helps !
a only contains {'A', 'd'} - the remaining characters are written to the memory after a. In your case, you didn’t write over anything important, so the code appears to function as expected.
Appears to. The behavior of writing past the end of an array is undefined, meaning there’s no requirement on the compiler or runtime environment to handle the situation in any particular way. C does not require a bounds check on array accesses - it won’t throw an exception if you write past the end of an array. Your code may crash immediately, you may wind up with corrupted data, it may leave your program in a bad state such that it crashes later (those situations are fun to debug, let me tell you), or it may work with no apparent problems.
It is up to you, the programmer, to make sure the target array is large enough to hold the new value. The language doesn’t protect you at all here.

array of pointers in c the code should not run

//this code should give segmentation error....but it works fine ....how is it possible.....i just got this code by hit and trail whle i was trying out some code of topic ARRAY OF POINTERS....PLZ can anyone explain
int main()
{
int i,size;
printf("enter the no of names to be entered\n");
scanf("%d",&size);
char *name[size];
for(i=0;i<size;i++)
{
scanf("%s",name[i]);
}
printf("the names in your array are\n");
for(i=0;i<size;i++)
{
printf("%s\n",&name[i]);
}
return 0
The problem in your code (which is incomplete, BTW; you need #include <stdio.h> at the top and a closing } at the bottom) can be illustrated in a much shorter chunk of code:
char *name[10]; // make the size an arbitrary constant
scanf("%s", name[0]); // Read into memory pointed to by an uninitialized pointer
(name could be a single pointer rather than an array, but I wanted to preserve your program's structure for clarity.)
The pointer name[0] has not been initialized, so its value is garbage. You pass that garbage pointer value to scanf, which reads characters from stdin and stores them in whatever memory location that garbage pointer happens to point to.
The behavior is undefined.
That doesn't mean that the program will die with a segmentation fault. C does not require checking for invalid pointers (nor does it forbid it, but most implementations don't do that kind of checking). So the most likely behavior is that your program will take whatever input you provide and attempt to store it in some arbitrary memory location.
If the garbage value of name[0] happens to point to a detectably invalid memory location, your program might die with a segmentation fault. That's if you're luck. If you're not, it might happen to point to some writable memory location that your program is able to modify. Storing data in that location might be harmless, or it might clobber some critical internal data structure that your program depends on.
Again, your program's behavior is undefined. That means the C standard imposes no requirements on its behavior. It might appear to "work", it might blow up in your face, or it might do anything that it's physically possible for a program to do. Apparently to behave correctly is probably the worst consequence of undefined behavior, since it makes it difficult to diagnose the problem (which will probably appear during a critical demo).
Incidentally, using scanf with a %s format specifier is inherently unsafe, since there's no way to limit the amount of data it will attempt to read. Even with a properly initialized pointer, there's no way to guarantee that it points to enough memory to hold whatever input it receives.
You may be accustomed to languages that do run-time checking and can reliably detect (most) problems like this. C is not such a language.
I'm not sure what's your test case (No enough reputation to post a comment). I just try to input it with 0 and 1\n1\n2\n.
It's a little complex to explain the detail. However, Let's start it :-). There are two things you should know. First, main() is a function. Second, you use a C99 feature, variable-length array or gnu extension, zero-length array (supported by gcc), on char *name[size];.
main() is a function, so all the variable declared in this function is local variables. Local variables locate at stack section. You must know about it first.
If you input 1\n1\n2\n, the variable-length array is used. The implementation of it is also to allocate it on stack. Notice that value of each element in array is not initialized as 0. That is the possible answer for you to execute without segmentation fault. You cannot make sure that it'll point to the address which isn't writable (At least failed on me).
If the input is 0\n, you will use extension feature, zero-length array, supported by GNU. As you saw, it means no element in array. The value of name is equal to &size, because size is the last local variable you declared before you declared name[0] (Consider stack pointer). The value of name[0] is equal to dereference to &size, that's zero (='\0') , so it will work fine.
The simple answer to your question is that a segmentation fault is:
A segmentation fault (aka segfault) are caused by a program trying to read or write an illegal memory location.
So it all depends upon what is classed as illegal. If the memory in question is a part of the valid address space, e.g. the stack, for the process the program is running, it may not cause a segfault.
When I run this code in a debugger the line:
scanf("%s, name[i]);
over writes the content of the size variable, clearly not the intended behaviour, and the code essentially goes into an infinite loop.
But that is just what happens on my 64 bit Intel linux machine using gcc 5.4. Another environment will probably do something different.
If I put the missing & in front of name[i] it works OK. Whether that is luck, or expertly exploiting the intended behaviour of C99 variable length arrays, as suggested. I'm afraid I don't know.
So welcome to the world of subtle memory overwriting bugs.

why when declare a dynamic variable, reserves more than specified

I have the following code
char *str = (char *) malloc(sizeof(char)*5);
printf("Enter a string: ");
scanf("%s", str);
printf("%s\n", str);
This code supposed will reserve 5 places in memory ex: 5 * 8 bit, this mean that will stores five characters.
Now, when enter any number of characters (not up to five only), does not occur any error whether in compile time or in run time.
is this normal? or there is an error I did not understand in my code ?
C will not prevent you from shooting yourself in the foot. scanf will happily overwrite the buffer given to it, invoking undefined behavior. This error is not reliably detectable at runtime and will silently corrupt memory and break the runtime of your application in unpredictable ways.
It is your responsibility as the programmer to prevent this from happening - in this case, for example, by replacing scanf with much safer fgets.
You've allocated 5 bytes, but scanf will happily continue writing into *un*allocated memory. This is a buffer overflow, and the C runtime assumes you know what you are doing; no bounds checking is performed.
Don't use scanf. Use fgets to read a line of at most 5 bytes:
char *str = malloc(5);
fgets(str, 5, stdin);
If you type a line with more than 4 characters, fgets simply discards the extra characters.
You have indeed allocated space only for 5 bytes (i.e., strings up to 4 characters + the terminating NUL), but your scanf does not know that. It will blissfully overflow the allocated buffer. You are responsible for ensuring that this does not happen; you need to change your code accordingly. Overflowing the buffer is undefined behaviour so in theory “anything” may happen or not happen as a consequence, but in practice it tends to overwrite other things in adjacent memory, corrupting the contents of other variables and possibly even program code (leading to an exploit where a malicious user can craft the input string so as to execute arbitrary code).
(As an additional note, sizeof char is always 1 by definition, you do not need to multiply with it.)
You asked for 5 chars, you get memory that can contain at least 5 chars; the allocator is free to give you more memory for its internal reasons, but there's no standard way to know how much more it gave to you.
Besides, normally there's no immediate error even if you actually overflow a buffer like you did - the standard does not mandate bounds checking, it just says that this is "undefined behavior", i.e. anything can happen, from "your program seems to work" to "universe death" passing through nasal demons.
What actually happens in most implementation is that you will happily write over whatever happens to be after your buffer - typically other local variables or the return address for stack variables, other memory blocks and allocator's data structures for heap allocations. The effect usually is "impossible" bugs due to changing unrelated variables, heap corruption (typically discovered when you call free), segmentation faults and the like.
You must be very careful with this kind of errors, since buffer overflows not only undermine the stability of your application, but can also be exploited for security breaches. Thus, never carelessly write in a buffer - always use functions that allow you to specify the total size of the buffer and that stop at its boundaries.
When you allocate memory dynamically, more space will be allocated than the specified. Generally malloc implementations round the size requested to the multiple of 8 or 16 or some other 2^n. That's may be the one of the reason that you are not getting any error.

Resources