Why does this simple C program crash at runtime? - c

I tried the following simple C program but it crashes at runtime without giving any output. What is wrong here? How can I solve this problem?
#include <stdio.h>
#include <string.h>
int main(void)
{
char *s1="segmentation";
char *s2="fault";
char *s3=strcat(s1,s2);
printf("concatanated string is %s",s3);
}

So this is the agregated answer for this question:
you should not try to alter string literal in any way. according to the C standard , altering string literals causes undefined behaviour:
"It is unspecified whether these arrays are distinct provided their
elements have the appropriate values. If the program attempts to
modify such an array, the behavior is undefined."
but let's say for the discussion that s1 is not string literal - you still need have enough buffer for strcat to work on - strcat finds the nul termination character and start writing on it the string you're appending. if your buffer is not big enough - you will try to write outside the bounderies of your array - causing again undefined behaviour.

Because strcat append functions on his first argument.
Ie the result will be store on s1 not on s3
You should allocate more memory for s1.
Ie :
char* s1 = malloc(sizeof(char) * (13 + 6)); //length of your 2 strings
strcpy(s1, "segmentation");
char *s2="fault";
strcat(s1,s2);
printf("concatanated string is %s",s1);

Others are focusing on there is not enough space in s1 for string concatenation. However, the bigger problem here is you are trying to modify a string literal, which is undefined behavior. Defining s1 as a char array that has enough space should work:
char s1[20] = "segmentation";
char *s2 = "fault";
strcat(s1,s2);
printf("concatanated string is %s",s1);

char *s1="segmentation";
s1 is an immutable string, which will be reside in read-only memory. If you look at the strcat definition:
char *strcat(char *dest, const char *src) here
dest -- This is pointer to the destination array, which should contain a C string, and should be large enough to contain the concatenated resulting string.
so when you are calling char *s3=strcat(s1,s2); you are trying to modify the immutable string which result in segmentation fault.

The most problematic thing here is that you declared s1 and s2 as char * and not as const char* - always use const in such case - this is read-only memory when you initialize a string this way.
If you want to extend the string in s1, you should not initialize it as you did, but you should allocate the memory for s1 on the stack or in the dynamic memory.
Example for allocating on the stack:
char s1[100] = "segmentation";
Example for allocating in the dynamic memory:
char *s1 = malloc(100 * sizeof(char));
strcpy(s1, "segmentation");
I used here 100 as I assume that this is enough for your string. You should always allocate a number that is at least the length of your string + 1

Found a similar one here on comp.lang.c It also answers in depth.
the main problem here is that space for the concatenated result is not
properly allocated. C does not provide an automatically-managed string
type. C compilers allocate memory only for objects explicitly
mentioned in the source code (in the case of strings, this includes
character arrays and string literals). The programmer must arrange for
sufficient space for the results of run-time operations such as string
concatenation, typically by declaring arrays, or by calling malloc.
strcat() performs no allocation; the second string is appended to the
first one, in place. The first (destination) string must be writable
and have enough room for the concatenated result. Therefore, one fix
would be to declare the first string as an array:
The original call to strcat in the question actually has two problems:
the string literal pointed to by s1, besides not being big enough for
any concatenated text, is not necessarily writable at all.

look at the definition of strcat()
char *strcat(char *dest, const char *src)
dest -- This is pointer to the destination array, which should contain a C string, and should be large enough to contain the concatenated resulting string.
src -- This is the string to be appended. This should not overlap the destination.
s1 is not enough to hold the concatenated string, which cause to write beyond the limit. It causes the run-time failure.
try this,
char *s1="segmentation";
char *s2="fault";
char* s3 = malloc(sizeof(s1) + sizeof(s2));
strcpy(s3, s1);
strcat(s3, s2);

Related

Does setting a string char to null cause a memory leak in C?

This seems like a silly question, but I couldn't find the answer.
Anyways, if you set an arbitrary character to null in a string,
then free the string, does that cause a memory leak?
I suppose my knowledge of how the free function works is limited.
/*
char *
strchr(const char *s, int c);
char *
strrchr(const char *s, int c);
The strchr() function locates the first occurrence of c (converted to a
char) in the string pointed to by s. The terminating null character is
considered part of the string; therefore if c is ‘\0’, the functions
locate the terminating ‘\0’.
The strrchr() function is identical to strchr() except it locates the
last occurrence of c.
*/
char* string = strdup ("THIS IS, A STRING WITH, COMMAS!");
char* ch = strrchr( string, ',' );
*ch = 0;
free( string );
/*
The resulting string should be: "THIS IS, A STRING WITH"
When the string pointer is freed, does this result in a memory leak?
*/
Not a stupid question in my opinion.
TLDR: no you do not cause a memory leak.
Now the longer answer: free has no idea what a string is. If you pass it a char* or an int* it could not care less.
The way malloc and free works is the following: when you call malloc you supply a size and receive a pointer with the promise of that many bytes being reserved on the heap from the position of the pointer onwards. However at that point the size and position are also saved internally in some way (this depends and is an implementation detail).
Now when you call free it does not need to know the size, it can just remove the entry your pointer belongs to together with the size
Addendum: also not every char* points to a string, it just so happens that "abcd" becomes a null terminated char* pointing to the 'a', but a char* itself points to a single char, not multiple
malloc only allocates the chunk of memory and gives you the reference to it. If you do not read or write outside the boundaries of this chunk you can do whatever you want with it.

strncat() is copying to the same string again

I am trying to concatenate two strings in C programming. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
/* code */
char s1[3],s2[34];
strncat(s1,"mv ",3);
strncat(s2," /home/xxxxxxx/.local/share/Trash/",34);
printf("%s \n",s1);
return 0;
}
when I try to print the value in s1 it prints mv /home/xxxxxxx/.local/share/Trash as the output. Why is the value i am putting for s2 getting added with the string s1? If the question is already asked please put the link.
You have undefined behavior in your code, as neither s1 nor s2 are initialized. Uninitialized (non-static) local variables have indeterminate values, and it's unlikely that they have the string terminator that strncat needs to find the end of the string to know where to append the source string.
After you fix the above, you also have another case of undefined behavior when strncat tries to write the string terminator beyond the end of the arrays.
Also, you're not concatenating the two strings, as s1 and s2 are two unrelated arrays, you just append the literal strings to the end of the two arrays but not together.
What you could do is to allocate an array big enough to hold both strings, and the string terminator, then copy the first string into the array, and then append the second string.
Or not use e.g. snprintf (or _snprintf is using the Microsoft Windows runtime library) to construct the string.
char s[100];
snprintf(s, sizeof(s), "mv %s %s", somepath, someotherpath);
s1 is defined as
char s1[3],
that is it has three elements (characters). When strncat was executed
strncat(s1," mv",3);
this three elements were filled with { ' ', 'm', 'y' }
After that this array does not have the terminating zero.
Format specifier %s in printf function outputs a character array until the terminatig zero will be encountered. As array s1 does not have the terminating zero then the printf continues to output all bytes that are beyond the array. because after array s1 there is array s2
char s1[3],s2[34];
then it also is outputed until the terminating zero will be encountered.
Take into account that function strncat requires that the target string would be zero terminated. However you did not initialize s1. So the behaviour of the program is undefined.
If you want that the program would work correctly you have to define array s1 as having four characters
char s1[4] = { '\0' },s2[34];
strncat(s1,"mv ",4);
Or it would be simpler to write
char s1[4] = { '\0' },s2[34];
strcat( s1, "mv " );
Or even the following way
char s1[4],s2[34];
strcpy( s1, "mv " );
that is it would be better to use function strcpy instead of strncpy
when I try to print the value in s1 it prints mv /home/ashwini/.local/share/Trash as the output.
This is undefined behavior: s1 is not null-terminated, because it has a three-character string in a space of three characters; there's no space for the null terminator.
Your s2 string buffer happens to be located in the adjacent region of memory, so it gets printed as well, until printf runs into the null terminator of s2.
Allocating more memory to s1 and accounting for null termination would fix this problem:
char s1[4],s2[36];
s1[0] = '\0';
strncat(s1," mv", 4);
s2[0] = '\0';
strncat(s2," /home/xxxxxxx/.local/share/Trash/", 36);
However, strncat is not a proper function for working with regular strings: it is designed for use with fixed-length strings, which are no longer in widespread use. Unfortunately, C standard library does not include strlcat, which has proper semantic for "regular" C strings. It is available on many systems as a library extension, though.
Demo.

string manipulations in C

Following are some basic questions that I have with respect to strings in C.
If string literals are stored in read-only data segment and cannot be changed after initialisation, then what is the difference between the following two initialisations.
char *string = "Hello world";
const char *string = "Hello world";
When we dynamically allocate memory for strings, I see the following allocation is capable enough to hold a string of arbitary length.Though this allocation work, I undersand/beleive that it is always good practice to allocate the actual size of actual string rather than the size of data type.Please guide on proper usage of dynamic allocation for strings.
char *str = (char *)malloc(sizeof(char));
scanf("%s",str);
printf("%s\n",str);
1.what is the difference between the following two initialisations.
The difference is the compilation and runtime checking of the error as others already told about this.
char *string = "Hello world";--->stored in read only data segment and
can't be changed,but if you change the value then compiler won't give
any error it only comes at runtime.
const char *string = "Hello world";--->This is also stored in the read
only data segment with a compile time checking as it is declared as
const so if you are changing the value of string then you will get an
error at compile time ,which is far better than a failure at run time.
2.Please guide on proper usage of dynamic allocation for strings.
char *str = (char *)malloc(sizeof(char));
scanf("%s",str);
printf("%s\n",str);
This code may work some time but not always.The problem comes at run-time when you will get a segmentation fault,as you are accessing the area of memory which is not own by your program.You should always very careful in this dynamic memory allocation as it will leads to very dangerous error at run time.
You should always allocate the amount of memory you need correctly.
The most error comes during the use of string.You should always keep in mind that there is a '\0' character present at last of the string and during the allocation its your responsibility to allocate memory for this.
Hope this helps.
what is the difference between the following two initialisations.
String literals have type char* for legacy reasons. It's good practice to only point to them via const char*, because it's not allowed to modify them.
I see the following allocation is capable enough to hold a string of arbitary length.
Wrong. This allocation only allocates memory for one character. If you tried to write more than one byte into string, you'd have a buffer overflow.
The proper way to dynamically allocate memory is simply:
char *string = malloc(your_desired_max_length);
Explicit cast is redundant here and sizeof(char) is 1 by definition.
Also: Remember that the string terminator (0) has to fit into the string too.
In the first case, you're explicitly casting the char* to a const one, meaning you're disallowing changes, at the compiler level, to the characters behind it. In C, it's actually undefined behaviour (at runtime) to try and modify those characters regardless of their const-ness, but a string literal is a char *, not a const char *.
In the second case, I see two problems.
The first is that you should never cast the return value from malloc since it can mask certain errors (especially on systems where pointers and integers are different sizes). Specifically, unless there is an active malloc prototype in place, a compiler may assume that it returns an int rather than the correct void *.
So, if you forget to include stdlib.h, you may experience some funny behaviour that the compiler couldn't warn you about, because you told it with an explicit cast that you knew what you were doing.
C is perfectly capable of implicit casting between the void * returned from malloc and any other pointer type.
The second problem is that it only allocates space for one character, which will be the terminating null for a string.
It would be better written as:
char *string = malloc (max_str_size + 1);
(and don't ever multiply by sizeof(char), that's a waste of time - it's always 1).
The difference between the two declarations is that the compiler will produce an error (which is much preferable to a runtime failure) if an attempt to modify the string literal is made via the const char* declared pointer. The following code:
const char* s = "hello"; /* 's' is a pointer to 'const char'. */
*s = 'a';
results in the VC2010 emitted the following error:
error C2166: l-value specifies const object
An attempt to modify the string literal made via the char* declared pointer won't be detected until runtime (VC2010 emits no error), the behaviour of which is undefined.
When malloc()ing memory for storing of strings you must remember to allocate one extra char for storing the null terminator as all (or nearly all) C string handling functions require the null terminator. For example, to allocate a buffer for storing "hello":
char* p = malloc(6); /* 5 for "hello" and 1 for null terminator. */
sizeof(char) is guaranteed to be 1 so is unrequired and it is not necessary to cast the return value of malloc(). When p is no longer required remember to free() the allocated memory:
free(p);
Difference between the following two initialisations.
first, char *string = "Hello world";
- "Hello world" stored in stack segment as constant string and its address is assigned to pointer'string' variable.
"Hello world" is constant. And you can't do string[5]='g', and doing this will cause a segmentation fault.
Where as 'string' variable itself is not constant. And you can change its binding:
string= "Some other string"; //this is correct, no segmentation fault
const char *string = "Hello world";
Again "Hello world" stored in stack segment as constant string and its address is assigned to 'string' variable.
And string[5]='g', and this cause segmentation fault.
No use of const keyword here!
Now,
char *string = (char *)malloc(sizeof(char));
Above declaration same as first one but this time you are assignment is dynamic from Heap segment (not from stack)
The code:
char *string = (char *)malloc(sizeof(char));
Will not hold a string of arbitrary length. It will allocate a single character and return a pointer to char character. Note that a pointer to a character and a pointer to what you call a string are the same thing.
To allocate space for a string you must do something like this:
char *data="Hello, world";
char *copy=(char*)malloc(strlen(data)+1);
strcpy(copy,data);
You need to tell malloc exactly how many bytes to allocate. The +1 is for the null terminator that needs to go onto the end.
As for literal string being stored in a read-only segment, this is an implementation issue, although is pretty much always the case. Most C compilers are pretty relaxed about const'ing access to these strings, but attempting to modify them is asking for trouble, so you should always declare them const char * to avoid any issues.
That particular allocation may appear to work as there's probably plenty of space in the program heap, but it doesn't. You can verify it by allocating two "arbitrary" strings with the proposed method and memcpy:ing some long enough string to the corresponding addresses. In the best case you see garbage, in the worst case you'll have segmentation fault or assert from malloc or free.

C - strcpy pointer

I want to ask about strcpy. I got problem here. Here is my code:
char *string1 = "Sentence 1";
char *string2 = "A";
strcpy(string1, string2);
I think there is no problem in my code there. The address of the first character in string1 and string2 are sent to the function strcpy. There should be no problem in this code, right?
Anybody please help me solve this problem or explain to me..
Thank you.
There is a problem -- your pointers are each pointing to memory which you cannot write to; they're pointing to constants which the compiler builds into your application.
You need to allocate space in writable memory (the stack via char string1[<size>]; for example, or the heap via char *string1 = malloc(<size>);). Be sure to replace with the amount of buffer space you need, and add an extra byte at least for NULL termination. If you malloc(), be sure you free() later!
This gives undefined behaviour. The compiler may allow it, due to a quirk of history (string literals aren't const), but you're basically trying to overwrite data which on many platforms you simply cannot modify.
From linux man pages:
char *strcpy(char *dest, const char *src);
The strcpy() function copies the string pointed to by src,
including the terminating null byte ('\0'), to the buffer pointed to
by dest. The strings may not overlap, and the destination string
dest must be large enough to receive the copy.
You have a problem with your *dest pointer, since it's pointing to a string literal instead of allocated, modifiable memory. Try defining string one as char string1[BUFFER_LENGTH]; or allocate it dynamically with malloc().

I'm new to C, can someone explain why the size of this string can change?

I have never really done much C but am starting to play around with it. I am writing little snippets like the one below to try to understand the usage and behaviour of key constructs/functions in C. The one below I wrote trying to understand the difference between char* string and char string[] and how then lengths of strings work. Furthermore I wanted to see if sprintf could be used to concatenate two strings and set it into a third string.
What I discovered was that the third string I was using to store the concatenation of the other two had to be set with char string[] syntax or the binary would die with SIGSEGV (Address boundary error). Setting it using the array syntax required a size so I initially started by setting it to the combined size of the other two strings. This seemed to let me perform the concatenation well enough.
Out of curiosity, though, I tried expanding the "concatenated" string to be longer than the size I had allocated. Much to my surprise, it still worked and the string size increased and could be printf'd fine.
My question is: Why does this happen, is it invalid or have risks/drawbacks? Furthermore, why is char str3[length3] valid but char str3[7] causes "SIGABRT (Abort)" when sprintf line tries to execute?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main() {
char* str1 = "Sup";
char* str2 = "Dood";
int length1 = strlen(str1);
int length2 = strlen(str2);
int length3 = length1 + length2;
char str3[length3];
//char str3[7];
printf("%s (length %d)\n", str1, length1); // Sup (length 3)
printf("%s (length %d)\n", str2, length2); // Dood (length 4)
printf("total length: %d\n", length3); // total length: 7
printf("str3 length: %d\n", (int)strlen(str3)); // str3 length: 6
sprintf(str3, "%s<-------------------->%s", str1, str2);
printf("%s\n", str3); // Sup<-------------------->Dood
printf("str3 length after sprintf: %d\n", // str3 length after sprintf: 29
(int)strlen(str3));
}
This line is wrong:
char str3[length3];
You're not taking the terminating zero into account. It should be:
char str3[length3+1];
You're also trying to get the length of str3, while it hasn't been set yet.
In addition, this line:
sprintf(str3, "%s<-------------------->%s", str1, str2);
will overflow the buffer you allocated for str3. Make sure you allocate enough space to hold the complete string, including the terminating zero.
void main() {
char* str1 = "Sup"; // a pointer to the statically allocated sequence of characters {'S', 'u', 'p', '\0' }
char* str2 = "Dood"; // a pointer to the statically allocated sequence of characters {'D', 'o', 'o', 'd', '\0' }
int length1 = strlen(str1); // the length of str1 without the terminating \0 == 3
int length2 = strlen(str2); // the length of str2 without the terminating \0 == 4
int length3 = length1 + length2;
char str3[length3]; // declare an array of7 characters, uninitialized
So far so good. Now:
printf("str3 length: %d\n", (int)strlen(str3)); // What is the length of str3? str3 is uninitialized!
C is a primitive language. It doesn't have strings. What it does have is arrays and pointers. A string is a convention, not a datatype. By convention, people agree that "an array of chars is a string, and the string ends at the first null character". All the C string functions follow this convention, but it is a convention. It is simply assumed that you follow it, or the string functions will break.
So str3 is not a 7-character string. It is an array of 7 characters. If you pass it to a function which expects a string, then that function will look for a '\0' to find the end of the string. str3 was never initialized, so it contains random garbage. In your case, apparently, there was a '\0' after the 6th character so strlen returns 6, but that's not guaranteed. If it hadn't been there, then it would have read past the end of the array.
sprintf(str3, "%s<-------------------->%s", str1, str2);
And here it goes wrong again. You are trying to copy the string "Sup<-------------------->Dood\0" into an array of 7 characters. That won't fit. Of course the C function doesn't know this, it just copies past the end of the array. Undefined behavior, and will probably crash.
printf("%s\n", str3); // Sup<-------------------->Dood
And here you try to print the string stored at str3. printf is a string function. It doesn't care (or know) about the size of your array. It is given a string, and, like all other string functions, determines the length of the string by looking for a '\0'.
Instead of trying to learn C by trial and error, I suggest that you go to your local bookshop and buy an "introduction to C programming" book. You'll end up knowing the language a lot better that way.
There is nothing more dangerous than a programmer who half understands C!
What you have to understand is that C doesn't actually have strings, it has character arrays. Moreover, the character arrays don't have associated length information -- instead, string length is determined by iterating over the characters until a null byte is encountered. This implies, that every char array should be at least strlen + 1 characters in length.
C doesn't perform array bounds checking. This means that the functions you call blindly trust you to have allocated enough space for your strings. When that isn't the case, you may end up writing beyond the bounds of the memory you allocated for your string. For a stack allocated char array, you'll overwrite the values of local variables. For heap-allocated char arrays, you may write beyond the memory area of your application. In either case, the best case is you'll error out immediately, and the worst case is that things appear to be working, but actually aren't.
As for the assignment, you can't write something like this:
char *str;
sprintf(str, ...);
and expect it to work -- str is an uninitialized pointer, so the value is "not defined", which in practice means "garbage". Pointers are memory addresses, so an attempt to write to an uninitialized pointer is an attempt to write to a random memory location. Not a good idea. Instead, what you want to do is something like:
char *str = malloc(sizeof(char) * (string length + 1));
which allocates n+1 characters worth of storage and stores the pointer to that storage in str. Of course, to be safe, you should check whether or not malloc returns null. And when you're done, you need to call free(str).
The reason your code works with the array syntax is because the array, being a local variable, is automatically allocated, so there's actually a free slice of memory there. That's (usually) not the case with an uninitialized pointer.
As for the question of how the size of a string can change, once you understand the bit about null bytes, it becomes obvious: all you need to do to change the size of a string is futz with the null byte. For example:
char str[] = "Foo bar";
str[1] = (char)0; // I'd use the character literal, but this editor won't let me
At this point, the length of the string as reported by strlen will be exactly 1. Or:
char str[] = "Foo bar";
str[7] = '!';
after which strlen will probably crash, because it will keep trying to read more bytes from beyond the array boundary. It might encounter a null byte and then stop (and of course, return the wrong string length), or it might crash.
I've written all of one C program, so expect this answer to be inaccurate and incomplete in a number of ways, which will undoubtedly be pointed out in the comments. ;-)
Your str3 is too short - you need to add extra byte for null-terminator and the length of "<-------------------->" string literal.
Out of curiosity, though, I tried
expanding the "concatenated" string to
be longer than the size I had
allocated. Much to my surprise, it
still worked and the string size
increased and could be printf'd fine.
The behaviour is undefined so it may or may not segfault.
strlen returns the length of the string without the trailing NULL byte (\0, 0x00) but when you create a variable to hold the combined strings you need to add that 1 character.
char str3[length3 + 1];
…and you should be all set.
C strings are '\0' terminated and require an extra byte for that, so at least you should do
char str3[length3 + 1]
will do the job.
In sprintf() ypu are writing beyond the space allocated for str3. This may cause any type of undefined behavior (If you are lucky then it will crash). In strlen(), it is just searching for a NULL character from the memory location you specified and it is finding one in 29th location. It can as well be 129 also i.e. it will behave very erratically.
A few important points:
Just because it works doesn't mean it's safe. Going past the end of a buffer is always unsafe, and even if it works on your computer, it may fail under a different OS, different compiler, or even a second run.
I suggest you think of a char array as a container and a string as an object that is stored inside the container. In this case, the container must be 1 character longer than the object it holds, since a "null character" is required to indicate the end of the object. The container is a fixed size, and the object can change size (by moving the null character).
The first null character in the array indicates the end of the string. The remainder of the array is unused.
You can store different things in a char array (such as a sequence of numbers). It just depends on how you use it. But string function such as printf() or strcat() assume that there is a null-terminated string to be found there.

Resources