dynamic memory allocation and sprintf - c

While writing the following code I should get an error. The array size is given as zero(which I suppose is illegal) and furthermore sprintf is printing "abc" to a which has not been allocated any memory but I am getting the output as "abc". I cant understand why?
#include<stdio.h>
#include<string.h>
int main()
{
char a[0];
sprintf(a,"%s","abc");
printf("%s\n",a);
return 0;
}
I am getting the correct output when i am giving the array size to be 1,2,3 which should not be the case while it is giving segmentation fault for explicitly using a as a pointer ,i.e, using char *a(which is expected). Can somebody explain the internal working?

No, there's no reasonable explanation. By using an array which is smaller than the string to be printed, your program invokes undefined behavior. That means that literally anything can happen, including the fact that everything seems to be working fine. Undefined behavior doesn't mean that the program must crash, it means that it can crash.

Related

Character array initialization in C

I am trying to understand the array concept in string.
char a[5]="hello";
Here, array a is an character array of size 5. "hello" occupies the array index from 0 to 4. Since, we have declared the array size as 5, there is no space to store the null character at the end of the string.
So my understanding is when we try to print a, it should print until a null character is encountered. Otherwise it may also run into segmentation fault.
But, when I ran it in my system it always prints "hello" and terminates.
So can anyone clarify whether my understanding is correct. Or does it depends upon the system that we execute.
As ever so often, the answer is:
Undefined behavior is undefined.
What this means is, trying to feed this character array to a function handling strings is wrong. It's wrong because it isn't a string. A string in C is a sequence of characters that ends with a \0 character.
The C standard will tell you that this is undefined behavior. So, anything can happen. In C, you don't have runtime checks, the code just executes. If the code has undefined behavior, you have to be prepared for any effect. This includes working like you expected, just by accident.
It's very well possible that the byte following in memory after your array happens to be a \0 byte. In this case, it will look to any function processing this "string" as if you passed it a valid string. A crash is just waiting to happen on some seemingly unrelated change to the code.
You could try to add some char foo = 42; before or after the array definition, it's quite likely that you will see that in the output. But of course, there's no guarantee, because, again, undefined behavior is undefined :)
What you have done is undefined behavior. Apparently whatever compiler you used happened to initialize memory after your array to 0.
Here, array a is an character array of size 5. "hello" occupies the array index from 0 to 4. Since, we have declared the array size as 5, there is no space to store the null character at the end of the string.
So my understanding is when we try to print a, it should print until a null character is encountered.
Yes, when you use printf("%s", a), it prints characters until it hits a '\0' character (or segfaults or something else bad happens - undefined behavior). I can demonstrate that with a simple program:
#include <stdio.h>
int main()
{
char a[5] = "hello";
char b[5] = "world";
int c = 5;
printf("%s%s%d\n", a, b, c);
return 0;
}
Output:
$ ./a.out
helloworldworld5
You can see the printf function continuing to read characters after it has already read all the characters in array a. I don't know when it will stop reading characters, however.
I've slightly modified my program to demonstrate how this undefined behavior can create bad problems.
#include <stdio.h>
#include <string.h>
int main()
{
char a[5] = "hello";
char b[5] = "world";
int c = 5;
printf("%s%s%d\n", a, b, c);
char d[5];
strcpy(d, a);
printf("%s", d);
return 0;
}
Here's the result:
$ ./a.out
helloworld��world��5
*** stack smashing detected ***: <unknown> terminated
helloworldhell�p��UAborted (core dumped)
This is a classic case of stack overflow (pun intended) due to undefined behavior.
Edit:
I need to emphasize: this is UNDEFINED BEHAVIOR. What happened in this example may or may not happen to you, depending on your compiler, architecture, libraries, etc. You can make guesses to what will happen based on your understanding of different implementations of various libraries and compilers on different platforms, but you can NEVER say for certain what will happen. My example was on Ubuntu 17.10 with gcc version 7. My guess is that something very different could happen if I tried this on an embedded platform with a different compiler, but I cannot say for certain. In fact, something different could happen if I had this example inside of a larger program on the same machine.

strange thing about calloc [duplicate]

This question already has answers here:
Writing more characters than malloced. Why does it not fail?
(9 answers)
Why don't I get a segmentation fault when I write beyond the end of an array?
(4 answers)
Closed 6 years ago.
I was writing some code and I used the function calloc.
I understand that, when the first and the second arguments passed to this function are both zero, the function is going to alloc the necessary space for 0 elements, each of them with size 0, but here is the strange thing.
This program works fine even if n > 0. Why is that happening? I think it should display an error because I'm trying to write in a position of the array that doesn't exist. Thanks!
#include <stdio.h>
#include <stdlib.h>
int main(){
int n;
scanf("%d", &n);
int *test = calloc(0, 0);
for(int i = 0; i < n; i++){
test[i] = 100;
printf("%d ", test[i]);
}
return 0;
}
In C, a lot of wrong and "wrong" things don't display error messages from the compiler. In fact, you may not even see error messagens when you run the program -- but another person running your program in a different computer may see the error.
One important concept in C is called undefined behavior. To put it in simple terms, it means that the behavior of your program is unpredictable, but you can read more about this subject in this question: Undefined, unspecified and implementation-defined behavior.
Your program is undefined for a two reasons:
When either size or nmemb is zero, calloc() may return NULL. Your program is not checking the output of calloc(), so there's a good chance that when you do test[i] you are attempting to derreference a NULL pointer -- you should always check the result of calloc() and malloc().
When you call malloc() or calloc(), you are essentialy allocating dynamic memory for an array. You can use your pointer to access the elements of the array. But you can't access anything past the array. That is, if you allocate n elements you should not try to access the n+1-th element -- nether for reading.
Both items above make your program invoke undefined behavior. There might also be something undefined about accessing an empty object other than item #2 listed above, but I'm unsure.
You should always be careful about undefined behavior because, when your program invokes UB, it is essentialy unpredictable. You could see a compilation error, the program could give an error messagen, it could run successfuly without any problems or it could wipe out every single file in your hard disk.

As I allocate one byte of space ,then how is it possible to print largest integer of four byte?

I used a integer pointer which points to 1 byte of address in heap area.
Then I assigned the value of max integer at integer pointer.I think output of printf statement should be garbage value rather than correct value .How is it possible? Please explain.
#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
int main()
{
int *i;
i=malloc(sizeof(char));
*i=INT_MAX;
printf("%d",*i);
return 0;
}
C has no bounds checking neither at compile-time nor at run-time. If you write out of bounds of allocated memory you will have undefined behavior though.
When you read or write outside your memory bounds you invoke undefined behavior.
This means your program could crash, it could behave unpredictably or print unknown values, or it could appear to work properly. The fact that your program happened to print the expected value can't be depended on.
Under the hood, it probably has something to do with the implementation of malloc on your system and how it keeps track of allocated memory and whether it uses any buffer space in its allocations. But again, you can't depend on any of this.

C dynamic array element access

I'm learning C and trying to build an dynamic array. I found a great tutorial on this but I don't get it all the way. The code I have now is
typedef struct{
int size;
int capacity;
char *data;
}Brry;
void brry_init(Brry *brry){
brry->size = 0;
brry->capacity = 2;
brry->data = (char *)calloc(brry->capacity, sizeof(char));
}
void brry_insert(Brry *brry, char value){
brry->data[brry->size++] = value; //so do check here if I have enough memory, but checking something out
}
int main(void){
Brry brry;
brry_init(&brry);
for (int i = 0; i < 3; i++) {
brry_insert(&brry, 'a');
}
printf("%c\n", brry.data[2]);
return 0;
}
In my main function I add 3 element to the array, but it only allocated for 2. But when I print it it works just fine? I expected some strange value to be printed. Why is this or am I doing something wrong?
You are writing into a buffer you didn't allocate enough memory for. That it works is not guaranteed.
What you're trying now is to read from some junk value in memory, who knows, which sometimes leads to a segmentation fault and other times you are lucky and get some junk value, and it doesn't segfault.
Writing into junk memory will invoke undefined behavior, so better watch it.
If you do get errors it will almost always be a segfault, short for segmentation fault.
Read up on it here.
The technical for what you're doing by reading past the bounds of the array is called derefencing a pointer. You might also want to read more about that here.
Yes, you are indeed writing to the third element of a two element array. This means your program will exhibit undefined behavior and you have no guarantee of what is going to happen. In your case you got lucky and the program "worked", but you might not always be so lucky.
Trying to read/write past the end of the array results in undefined behaviour. Exactly what happens depends on several factors which you cannot predict or control. Sometimes, it will seem to read and/or write successfully without complaining. Other times, it may fail horribly and effectively crash your program.
The critical thing is that you should never try to use or rely on undefined behaviour. It's unfortunately a common rookie mistake to think that it will always work because one test happened to succeed. That's definitely not the case, and is a recipe for disaster sooner or later.

Why such an output

I executed this code after compiling in codeblocks:-
#include <stdio.h>
int main()
{
char arr[]="HELLO";
int a=arr;
return printf("...%s ,%s\n",arr,&a+1);
}
I got this output:-
...HELLO,HELLO
when I changed &a to a,printf returned -1.
I am not able to sort out this address logic ,please help.
(A friend gave me this code and asked its explanation, and I am not able to find it). So I would like to know why..
Thanks
You are telling printf to expect a string, but you are giving it the address of an int (&a). This invokes undefined behaviour, so anything could happen.
[In practice, what's probably happening is that the compiler places a directly below arr on the stack. So &a+1 ends up equal in value to &arr. printf then reinterprets that address as a pointer-to-char, and so ends up printing HELLO. If the compiler happened to arrange the stack differently, you'd observe different behaviour.]

Resources