program in c language
void main()
{
char *a,*b;
a[0]='s';
a[1]='a';
a[2]='n';
a[3]='j';
a[4]='i';
a[5]='t';
printf("length of a %d/n", strlen(a));
b[0]='s';
b[1]='a';
b[2]='n';
b[3]='j';
b[4]='i';
b[5]='t';
b[6]='g';
printf("length of b %d\n", strlen(b));
}
here the output is :
length of a 6
length of b 12
Why and please explain it.
thanks in advance.
You are assigning to pointer (which contains garbage) without allocating memory. What you are noticing is Undefined Behavior. Also main should return an int. Also it does not make sense to try and find the length of an array of chars which are not nul terminated.
This is how you can go about:
Sample code
When you declare any variable it comes with whatever it had in memory previously where your application is running, and since pointers are essentially numbers, whatever number it had referenced to some random memory address.
Then, when setting a[i], the compiler interprets that as you want to step sizeof(a) bytes forward, thus, a[i] is equal to the address (a + i*1) (1 because chars use one byte).
Finally, C-strings need to be NULL terminated (\0, also known as sentinel), and methods like strlen go over the length of the string until hitting the sentinel, most likely, your memory had a stray 0 somewhere that caused strlen to stop.
Allocate some memory and terminate the strings then it will work better
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main(){
char *a=malloc(10);
char *b=malloc(10);
if(a){
a[0]='s';
a[1]='a';
a[2]='n';
a[3]='j';
a[4]='i';
a[5]='t';
a[6]=(char)0;
printf("length of a %d\n", (int)strlen(a));
}else{
printf("Failed to allocate 10 bytes\n" );
}
if(b){
b[0]='s';
b[1]='a';
b[2]='n';
b[3]='j';
b[4]='i';
b[5]='t';
b[6]='g';
b[7]=(char)0;
printf("length of b %d\n", (int)strlen(b));
}else{
printf("Failed to allocate 10 bytes\n" );
}
free(a);
free(b);
}
Undefined behavior. That's all.
You're using an uninitialized pointer. After that, all bets are off as to what will happen.
Of course, we can attempt to explain why your particular implementation acts in a certain way but it'd be quite pointless outside of novelty.
The indexing operator is de-referencing the pointers a and b, but you never initialized those pointers to point at valid memory. Writing to un-initialized memory triggers undefined behavior.
You are simply "lucky" (or unlucky, it depends on your viewpoint) that the program doesn't crash, that the pointer values are such that you succeed in writing at those locations.
Note that you never write the termination character ('\0') to either string, but still get the "right" value from strlen(); this implies that a and b both point at memory that happens to be full of zeros. More luck.
This is a very broken program; that it manages to run "successfully" is because it's behavior is undefined, and undefined clearly includes "working as the programmer intended".
a and b are both char pointers. First of all, you didn't initialise them and secondly didn't terminate them with NULL.
Related
While working on dynamic memory allocation in C, I am getting confused when allocating size of memory to a char pointer. While I am only giving 1 byte as limit, the char pointer successfully takes input as long as possible, given that each letter corresponds to 1 byte.
Also I have tried to find sizes of pointer before and after input. How can I understand what is happening here? The output is confusing me.
Look at this code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int limit;
printf("Please enter the limit of your string - ");
gets(&limit);
char *text = (char*) malloc(limit*4);
printf("\n\nThe size of text before input is %d bytes",sizeof(text));
printf("\n\nPlease input your string - ");
scanf("%[^\n]s",text);
printf("\n\nYour string is %s",text);
printf("\n\nThe size of char pointer text after input is %d bytes",sizeof(text));
printf("\n\nThe size of text value after input is %d bytes",sizeof(*text));
printf("\n\nThe size of ++text value after input is %d bytes",sizeof(++text));
free(text);
return 0;
}
Check this output:
It works because malloc usually doesn't allocate the same number of bytes you pass to it.
It reserves memory multiple of "blocks". It usually reserve more memory to "cache" it for next malloc calls as an optimization. (it is an implementation specific)
check glibc malloc internals for example.
Using more memory than allocated by malloc is an undefined behavior. you may overwrite metadata of malloc saved on heap or corrupt other data.
Also I have tried to find sizes of pointer before and after input. How
can I understand what is happening here? The output is confusing me.
The size of pointer is fixed for all pointer types in a machine, it is usually 4/8 bytes depending on the address size. It doesn't have anything to do with data size.
Welcome to the world of Undefined Behaviour!
char *text = malloc(limit*4); (don't cast malloc in C) will make text point the the first element of an array of size limit*4.
C will not prevent you to write past the end of any array, simply the behaviour is undefined by the standard. It may work fine, or it may crash immediately, or you may experience abnormal behaviour later in the program.
Here, the underlying system call has probably allocated a full memory page (often 4k), and as you have not used another malloc you have just used a memory belonging to the process but still officially unused. But do not rely on that and never use it in production code.
And sizeof does not make sense with pointers. sizeof(text) is sizeof(char *) (same for sizeof(++text) for same reason) and is the size of a pointer (generaly 2, 4 or 8 bytes) and sizeof(*text) is sizeof(char) which by definition is 1.
C is confident that you as the programmer know how much memory you have asked, and will not try to use more. Anything can happen if you do (including expected result) but do not blame the language or the compiler if it breaks: only you will be guilty.
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.
I'm very new to C, and I'm not understanding this behavior. Upon printing the length of this empty array I get 3 instead of 0.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct entry entry;
struct entry{
char arr[16];
};
int main(){
entry a;
printf("%d\n",strlen(a.arr));
return 0;
}
What am I not understanding here?
The statement entry a; does not initialize the struct, so its value is likely garbage. Therefore, there's no guarantee that strlen on any of its members will return anything sensible. In fact, it might even crash the program, or worse.
There is no such thing as an "empty array" in C. Your array of char[16]; always contains 16 bytes - uninitialized as a local variable each char has an unspecified value. In addition, if none of these unspecified values happen to be 0, strlen will read outside the array and your code will have undefined behaviour.
Additionally strlen returns size_t and using %d to print this has undefined behaviour too; you must use %zu where z says that the corresponding argument is size_t.
(If by happenstance you're using the MSVC++ "C" compiler, do note that it might not support %zu. Get a real C compiler and C standard library instead.)
Here's the source code to strlen():
size_t strlen(const char *str)
{
const char *s;
for (s = str; *s; ++s);
return(s - str);
}
Wait, you mean there's source code to strlen()? Why yes. All the standard functions in C are themselves written in C.
This function starts at the memory address specified by str. It then uses the for function to start at that address, and then it goes forward, byte by byte, until it reaches zero. How does that for function do that? Well first it assigns s to str. Then, it checks the value s points to. If it's zero (i.e. if *s returns zero) then the for loop is done. If that value is not zero, the s pointer is incremented, and the zero check is done, over and over, until it finds a zero.
Finally, the distance that the s pointer has moved, minus the original pointer you passed in, is the result of strlen().
In other words, strlen() just walks through memory until it finds the next zero character, and it returns the number of characters from that point to the original pointer.
But, what if it doesn't find a zero? Does it stop? Nope. It will just trudge on and on until it finds a zero or the program crashes.
That is why strlen() is so confusing, and why it's source of many critical bugs in modern software. This doesn't mean you can't use it, but it does mean you must be very very careful to make sure that whatever you pass in is a null-terminated string (i.e. a set of zero or more non-zero characters, followed by a zero character.)
Remember also that in C, you basically have no idea what memory contains when you allocate it or set it aside. If you want it to be all zeros, then you need to make sure to fill it with zeros yourself!
Anyway, the answer to your question involves the use of the memset() function. You'll have to pass memset() the pointer to the beginning of your array, the length of that array, and the value to fill it with (in your case, zero of course!)
No initialization of a, this leads to undefined behavior.
C "strings" are '\0' terminated arrays of char. So strlen() will browse whole memory from given address until it either finds a '\0' or results in a segmentation fault.
What am I not understanding here?
Perhaps the mis-understanding is that auto variables, such as:
entry a;
are assigned memory from the process' stack. The pre-existing content of that stack memory is not zeroed-out for your benefit. Hence the value(s) of the elements of a, which will also be located on the process stack, will not be initially zeroed-out for your benefit. Rather, the entire content of a and its elements (including .arr) will contain bizarre and perhaps unexpected values.
C programmers learn to initialize auto variables by zeroing them out, or initializing them with a desirable value.
For example, the question code might do this as follows:
int main(){
entry a =
{
.arr[0] = 0
};
...
}
Or:
int main(){
entry a;
memset(&a, 0, sizeof(a));
...
}
I've written the following code :
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* ch = malloc(0 * sizeof(char));
int n = 300;
sprintf(ch, "%d", n);
printf("ch is : %s", ch);
return 0;
}
I've switched the 0 in the malloc function to different numbers to experiment and I tried putting 0 meaning allocating no memory but when I run the program it worked just fine and I don't understand why is that exactly because if I put 0 it's like allocating no memory at all so what's happening here ?
C lets you shoot yourself in the foot.
The malloc docs say
If size is zero, the return value depends on the particular library
implementation (it may or may not be a null pointer), but the returned
pointer shall not be dereferenced.
So your implementation is returning something other than zero. Your sprintf is writing into memory that it "shall not" write to. But in this particular case, you got lucky, and it was nowhere critical - at least nowhere that mattered in this short test program. In a longer program with more mallocs and frees, you almost surely would run into trouble.
malloc(0) is implementation-defined. It may return a null pointer, see C FAQ for detail.
The problem is in the following line:
printf("ch is : %s", ch);
ch is not a string (i.e, null-terminated char array), to print it with "%s" is illegal.
I am learning how to use pointers, so i wrote the below program to assign integer values in the interval [1,100] to some random locations in the memory.
When i read those memory locations, printf displays all the values and then gives me a segmentation fault. This seems an odd behavior, because i was hoping to see either all the values OR a seg fault, but not both at the same time.
Can someone please explain why i got to see both?
Thanks. Here is the code
#include <stdio.h>
#include <stdlib.h>
int main()
{
char first = 'f';
char *ptr_first = &first;
int i=1;
for(i=1;i<101;i++)
*(ptr_first+i) = i;
for(i=1;i<101;i++)
printf("%d\n", *(ptr_first+i));
return EXIT_SUCCESS;
}
Not odd at all. You are using your variable first, which is on the stack. What you essentially do is happily overwriting the stack (otherwise known from buffer overflows on the stack) and thus probably destroying any return address and so on.
Since main is called by the libc, the return to libc would cause the crash.
You're accessing memory past beyond that assigned to first. It is just one character, and, through the ptr_first pointer, you're accessing 100 positions past this character to unreserved memory. This may lead to segfaults.
You have to ensure the original variable has enough memory reserved for the pointer accesses. For example:
char first[100];
This will convert first in an array of 100 chars (basically a memory space of 100 bytes that you can access via pointer).
Note also that you're inserting int into the char pointer. This will work, but the value of the int will be truncated. You should be using char as the type of i.
since ptr_first pointer is pointing to a char variable first. Now when you are incrementing ptr_first, so incremented memory address location can be out of process memory address space, thats why kernel is sending segmentation fault to this process.