Modifying value of char pointer in c produces segfault - c

The following code produces a segmentation fault on my system. I can't figure out why. Any help would be appreciated.
#include<stdio.h>
int main() {
char * a = "abc";
*a = 'c';
printf("%c\n", *a);
return 0;
}

The standard explicitly lists this as undefined behavior in §J.2:
— The program attempts to modify a
string literal (6.4.5)
If you want to copy it into a local array, do:
char a[] = "abc";
a is an array on the stack, and you can modify it freely.

Attempting to modify a string literal causes undefined behaviour.

Related

Why does this C program throw a segmentation fault at runtime?

I'm declaring character array as char* string. And then I declare other pointer which again refer to original string, then when I'm going to change any thing on that string, at runtime program throws segmentation fault.
#include <string.h>
#include <ctype.h>
int main(void)
{
char* s = "random";
char* t = s;
*t = 'R'; // ----> Segmentation fault
t[0] = toupper(t[0]); // ----> Segmentation fault
*s = 'R'; // ----> Segmentation fault
s[0] = 'R'; // ----> Segmentation fault
printf("s is : %s , address : %p \n", s,s);
printf("t is : %s , address : %p \n", t,t);
return 0;
}
even this is not working :
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
char *p = "random";
*p = 'N'; // ----> Segmentation fault
return 0;
}
I'm declaring character array as char* string.
This is where your problems begin! Although pointers and arrays have some things in common, syntactically, they are not the same. What you are doing in the line copied below is declaring s as a pointer to a char and initializing that pointer with the address of the string literal you provide.
char* s = "random";
As a string literal, the compiler is allowed to (though not obliged to) allocate memory for that data in read-only memory; thus, when you attempt (later) to modify the character pointed to by (the address in) the s variable (or any other pointer, such as your t, which contains the same address), you will experience undefined behaviour. Some systems will cause your program to crash ("Segmentation fault"), others may silently allow you to 'get away' with it. Indeed, you may even get different result with the same code at different times.
To fix this, and to properly declare a character array, use the [] notation:
char a[] = "random";
This will declare a as a (modifiable) array of characters (whose size is determined, in this case, by the initial value you give it - 7, here, with the terminating nul character included); then, the compiler will initialize that array with a copy of the string literal's data. You are then free to use an expression like *a to refer to the first element of that array.
The following short program may be helpful:
#include <stdio.h>
int main()
{
char* s = "random";
*s = 'R'; // Undefined behaviour: could be ignored, could crash, could work!
printf("%s\n", s);
char a[] = "random";
*a = 'R'; // Well-defined behaviour - this will change the first letter of the string.
printf("%s\n", a);
return 0;
}
(You may need to comment-out the lines that use s to get the code to run to the other lines!)
"random" is a constant string literal. It is placed by OS into the protected Read-Only Memory (CPU is instructed by OS to prevent write operations in this memory).
's' and 't' both point to this protected read-only memory region.
Once you tries to write into it, CPU detects this attempt and generates exception.
you try to modify the string literal. It is an Undefined Behavoiur and everything may happen including the segfault.
from the C standard what is an UB:
—The program attempts to modify a string literal (6.4.5).

C String Length using null

I know the C language has dynamic length strings whereby it uses the special character null (represented as 0) to terminate a string - rather than maintaining the length.
I have this simple C code that creates a string with the null character in the fifth index:
#include <stdio.h>
#include <stdlib.h>
int main () {
char * s= "sdfsd\0sfdfsd";
printf("%s",s);
s[5]='3';
printf("%s",s);
return 0;
}
Thus, a print of the string will only output up to the fifth index. Then the code changes the character at the fifth index to a '3'. Given my understanding, I assumed it would print the full string with the 3 instead of the null, as such:
sdfsdsdfsd3sfdfsd
but instead it outputs:
sdfsdsdfsd
Can someone explain this?
This program exhibits undefined behavior because you modify a read-only string literal. char* s = "..." makes s point to constant memory; C++ actually disallows pointing non-const char* to string literals, but in C it's still possible, and we have to be careful (see this SO answer for more details and a C99 standards quote)
Change the assignment line to:
char s[] = "sdfsd\0sfdfsd";
Which creates an array on the stack and copies the string to it, as an initializer. In this case modifying s[5] is valid and you get the result you expect.
String literals can not be changed because the compiler put the string literals into a read-only data-section (but this might vary by underlying platform). The effect of attempting to modify a string literal is undefined.
In your code:
char * s= "sdfsd\0sfdfsd"
Here, s is char pointer pointing to a string "sdfsd\0sfdfsd" stored in read-only memory, making it immutable.
Here you are trying to modify the content of read-only memory:
s[5]='3';
which leads to undefined behavior.
Instead, you can use char[]:
#include <stdio.h>
int main () {
char a[] = "sdfsd\0sfdfsd";
char * s = a;
printf("%s",s);
s[5]='3';
printf("%s\n",s);
return 0;
}
This operation has failed:
s[5] = 3;
You're trying to change a string literal, which is always read-only. My testing shows the program exited with segfault:
Segmentation fault (core dumped)
You should store it in an array (or allocated memory) before any attempts to change it:
char s[] = "sdfsd\0sfdfsd";
With the above change, the program works as intended.
#include <stdio.h>
int main(){
char x[10] = "aa\0a";
x[2] = '1';
puts(x);
printf("\n\n\nPress any key to exit...");
getch();
return 0;
}
Output: aa1a

How to use strcpy for pointers?

Why it stops working? Can't we pass the name of the pointer as an argument for strcpy? if I change it to strcpy(&a,&b); it works.
#include <stdio.h>
int main() {
char *a;
a = "aabtyn";
char *b;
b = "mihli";
strcpy(a,b);
printf("%s-%s\n",a,b);
return 0;
}
Can't we pass the name of the pointer as an argument for strcpy?
Yes, we can. However, it is also important that the destination pointer points to a writeable memory; in your case, neither a nor b point to memory that can be written.
if I change it to strcpy(&a,&b); it works.
If it appears to work on your system, it does so by mistake. What you see is undefined behavior. In order for strcpy to work you need to do one of the following:
Allocate a in automatic memory by defining it as char a[] = "aabtyn";, or
Allocate a in dynamic memory by calling char *a = malloc(7); You need seventh byte for null terminator.
According to the C Standard (6.4.5 String literals)
7 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.
You declared two pointers to string literals
char *a;
a = "aabtyn";
char *b;
b = "mihli";
Then in this statement
strcpy(a,b);
you are trying to modify the first string literal. So the behaviour of the program is undefined.
As for this statement
strcpy(&a,&b);
then there is an attempt to copy the value of one pointer to another pointer. This call aslo has undefined behaviour. But if the value of the second pointer is zero-terminated then this call can be equivalent to
a = b;
So the first pointer just reassigned. Though in any case there is undefined behaviour.
A valid program can look the following way
#include <stdio.h>
#include <string.h>
int main( void )
{
char s[] = "aabtyn";
char *a = s;
char *b;
b = "mihli";
strcpy(a,b);
printf("%s-%s\n",a,b);
return 0;
}
If you have:
char source[80],dest[80];
Initialize source, then:
strcpy(dest,source);
But if you have:
char *pd,*ps;
Initialize source,and malloc storage for *pd, then:
strcpy(&pd,&ps);
And remember to have free(pd); somewhere before exit(0);

Segmentation fault (core dumped) in C, The C Programming Language by K&R Exercise 2.5 [duplicate]

This question already has answers here:
Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s[]"?
(19 answers)
Closed 9 years ago.
I am writing a code for squeeze(s1,s2) that deletes each character in string s1 that matches any character in string s2 and I get "Segmentation fault (core dumped)" when I try to run the program.
I believe the error comes from in how i call the function inside the main(). I am a beginner and I don't know how to call functions. Please help!
#include<stdio.h>
void squeezer(char s[], char c[]);
main()
{
squeezer("abcdefgabcdefgabcdefg", "abcd");
}
void squeezer(char s[], char c[])
{
int i,j,k,z;
for(k=0; c[k] != '\0'; k++) {
for(i=j=0;s[i] != '\0';i++) {
if (s[i] != c[k]) {
s[j++] = s[i];
}
s[j] = '\0';
}
}
for(z=0; z < j; z++)
printf("%c",s[z]);
}
You are passing string literal to your function and then trying to modify it. You can't modify a string literal. Modifying a string literal invokes undefined behavior. In such case you may get either expected or unexpected result You may get segmentation fault or program crash too.
You can change your main function as
int main(void)
{
char s1[] = "abcdefgabcdefgabcdefg";
char s2[] = "abcd";
squeezer(s1, s2);
}
Must read: comp.lang.c FAQ list · Question 1.32.
String literals are "constant", read-only. You cannot change them, and that is what squeezer() tries to do.
You're writing to string literals, which is undefined behaviour. If your compiler put them in read-only memory, then your program should segfault. Try making writable copies of your strings in main, like so:
int main(int argc, char** argv)
{
char s[] = "abcdefgabcdefgabcdefg";
char c[] = "abcd";
squeezer(s, c);
return 0;
}
Depending on the C compiler and operating system you are using, the string literal you pass to squeezer may be "read-only" -- i.e. immutable -- at run-time. This is the same mechanism meant to prevent modification of compiled code at run-time.
The fix is to allocte a character array large enough to hold s using malloc or declare a char s[80] in main or as a global variable and then use strcpy to copy your first string literal into s before passing it as the first argument to squeezer.
Alternatively, you could pass the allocated or declared array variable as a third argument to squeezer and copy the "squeezed" string into it. Or, if you want to make squeezer as robust as you can, allocate a result array with malloc in squeezer that is strlen(s) in size, use it to accumulate the "squeezed" letters, and then return the pointer to the allocted array from squeezer whose return type will have changed from void to char *.

How do I avoid segmentation fault?

The code is self-explanatory, but it gives me segmentation fault, why? :\
#include <stdio.h>
int main(void)
{
char *c = "Hella";
*(c+4) = 'o';
printf("%s\n",c);
}
How to avoid it?
Don't modify a string literal!
char *c = "Hella";
Declares a pointer c to a string literal "Hella" stored in implementation defined read only memory.
You are not allowed to modify this literal. An attempt to do so results in Undefined Behavior.
You are lucky that your program crashes, an Undefined Behavior does not always result in a crash but may cause your program to behave weirdly in any possible way.
What you need here is an array:
char c[] = "Hella";
Good Read:
What is the difference between char a[] = ?string?; and char *p = ?string?;?
Put your string into an array allocated onto the stack:
char c[] = "Hella";
Because as said, string literals are usually read-only.
the way you create c it points to a string literal. You can not modify it's contents. If you want to be able to do that use:
char c[6] = "Hella";
c[4] = o;
Or use a dynamically allocated char array.
You are trying to overwrite a literal. Really your code should read:
const char *c = "Hella";
Which kinda explains what is going on.
To overwrite your own memory:
char c[] = "Hella";
is safer.
You can not modify strings that are defined in code. Use strdup if you want to modify them.
#include <stdio.h>
int main(void)
{
char *c = strdup("Hella");
*(c+4) = 'o';
printf("%s\n",c);
free(c);
}

Resources