Using generic pointers for strings [duplicate] - c

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 8 years ago.
I was trying out a sample program to understand about the generic swap function.
/* A simple generic swap function */
#include<stdio.h>
#include<string.h>
void swap(void* xp,void* yp,int size){
//void temp = *xp; // we cant declare a variable as void , as we need to konw to de-reference as its not specifying any size info
// Hence used the smallest type info - char
char buffer[size];
memcpy(buffer,xp,size);
memcpy(xp,yp,size);
memcpy(yp,buffer,size);
}
int main(){
int a = 10;
int b = 20;
double d=1.34;
double e=2.34;
char* s = "Hello";
char* t = "World";
printf("\n a : %s b : %s \n",s,t);
swap(s,t,sizeof(char*));
printf("\n a : %s b : %s \n",s,t);
return 0;
}
I got a segmentation fault when I ran the above program with the function call as swap(s,t,sizeof(char*)). But if I run it with swap(&s,&t,sizeof(char*)), I don't get any segmentation fault.
gdb o/p:
Breakpoint 2, swap (xp=0x4007ac, yp=0x4007b2, size=8) at swap_generic1.c:5
5 void swap(void* xp,void* yp,int size){
(gdb) s
8 char buffer[size];
(gdb) s
9 memcpy(buffer,xp,size);
(gdb) s
10 memcpy(xp,yp,size);
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b64fe4 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
what might be the cause of the problem. Is that when passed as s and t, the argument is assigned with the address of the strings "Hello" and "World" respectively, and the pointer increments goes sto some other location to fetch the values.

You are calling the swap functions with sizeof (char *), so you expect to only swap pointers. But you fail to pass pointers to the pointers, instead passing the values of the pointers themselves.
This will make swap() try to swap sizeof (char *) characters in the strings, which is not allowed since character literals generate constant data which cannot be written.
You should call it as:
swap(&s, &t, sizeof s);
to just swap the pointer values, not move any character data around.

char* s = "Hello";
char* t = "World";
Both are pointer pointing to string literal (constant string). The compiler puts that in a part of memory that is marked as read-only. If you try to change that it will result in a memory access violation.

The pointers you pass to your swap function are string literals and writing to an element in a string literal is undefined behaviour. That is why you get the segfault

Related

Why can't I change individual char of a string pointer in C? [duplicate]

In this statement:
char *a = "string1"
What exactly is string literal? Is it string1? Because this thread What is the type of string literals in C and C++? says something different.
Up to my knowledge
int main()
{
char *a = "string1"; //is a string- literals allocated memory in read-only section.
char b[] = "string2"; //is a array char where memory will be allocated in stack.
a[0] = 'X'; //Not allowed. It is an undefined Behaviour. For me, it Seg Faults.
b[0] = 'Y'; //Valid.
return 0;
}
Please add some details other than above mentioned points. Thanks.
Debug Output Showing error in a[0] = 'Y';
Reading symbols from /home/jay/Desktop/MI/chararr/a.out...done.
(gdb) b main
Breakpoint 1 at 0x40056c: file ddd.c, line 4.
(gdb) r
Starting program: /home/jay/Desktop/MI/chararr/a.out
Breakpoint 1, main () at ddd.c:4
4 {
(gdb) n
6 char *a = "string1";
(gdb) n
7 char b[] = "string2";
(gdb)
9 a[0] = 'Y';
(gdb)
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400595 in main () at ddd.c:9
You can look at string literal as "a sequence of characters surrounded by double quotes".
This string should be treated as read-only and trying to modify this memory leads to undefined behavior. It's not necessarily stored in read only memory, and the type is char[] and not const char[], but it is still undefined behavior. The reason the type is not const is backwards compability. C didn't have the const qualifier in the beginning. In C++, string literals have the type const char[].
So how come that you get segmentation fault?
The main point is that char *ptr = "string literal" makes ptr to point to the read-only memory where your string literal is stored. So when you try to access this memory: ptr[0] = 'X' (which is by the way equivalent to *(ptr + 0) = 'X'), it is a memory access violation.
On the other hand: char b[] = "string2"; allocates memory and copies string "string2" into it, thus modifying it is valid. This memory is freed when b goes out of scope.
Have a look at Literal string initializer for a character array

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).

strcpy pass initialized null pointer c [duplicate]

This question already has answers here:
Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer
(5 answers)
Closed 6 years ago.
I'm trying out the following code:
int main()
{
char *yo = "yo";
char *whaddup = NULL;
strcpy(whaddup,yo);
}
and I get a segfault. Complete C noob here - other places say I should initialize whaddup as an array. Why can't I pass in a pointer to null?
Just any strcpy documentation will tell you that the destination string should be a char array large enough to hold the string and the NUL terminator.
So what you need is something like
char* yo = "yo";
char* whaddup = malloc(strlen(yo)+1);
strcpy(whaddup, yo);
Or alternatively you could use strdup function which does this for you, but it's not standard as it's POSIX only.
You have to either declare whaddup as a character array or ideally allocate space for it with malloc.
int main()
{
char *yo = "yo";
char *whaddup = malloc(sizeof(char) * 8); // buffer for 8 characters
strcpy(whaddup,yo);
}
By initializing whaddup to NULL you are not giving it any space in memory, so even copying one character into it will result in a segmentation fault.
You can pass in a pointer to null, but you can not copy string from pointer to null.
The function char* strcpy(char* dest, const char* src) is copy string from address src to address dest, your dest is null.

Bad permissions for mapped region [duplicate]

This question already has answers here:
Why is this string reversal C code causing a segmentation fault? [duplicate]
(8 answers)
Closed 9 years ago.
I get an error when trying to run the following function:
char* reverseInPlace(char* src)
{
//no need to alloc or free memory
int i=0;
int size=mystrlen(src);
for(i=0;i<size;i++)
{
int j=size-i-1;
if(i<j)
{
char temp;
printf("Interchange start %d:%c with %d:%c",i,src[i],j,src[j]);
temp=src[i];
src[i]=src[j];//error occurs here
src[j]=temp;
printf("Interchange complete %d:%c and %d:%c",i,src[i],j,src[j]);
}
}
return src;
}
I call this code like this:
char* rev2=reverseInPlace("BeforeSunrise");
printf("The reversed string is %s\n",rev2);
The error looks like this:
Interchange start 0:B with 12:e
Process terminating with default action of signal 11 (SIGSEGV)
Bad permissions for mapped region at address 0x401165
Why does this error occur?
You are passing a constant string to your function.
String literals are of type char [N + 1] (where N is the length of the array) in C, but modifying them results in undefined behavior. Your compiler should have already issued a warning at that point.
If you wish to modify it then you have to create a copy:
char str[] = "BeforeSunrise";
char* rev2=reverseInPlace(str);
It's because you try to modify a string literal, which is a constant array, i.e. it's read-only.

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 *.

Resources