memcpy array vs pointer example and question [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 2 years ago.
This program illustrates my question:
#include "stdio.h"
#include "string.h"
void first_try() // segmentation fault
{
size_t numc = 1;
char *dest = "i "; // this is bad? i need to declare character array first? why?
char *src = "lone wolf c program\n";
memcpy(dest, src, numc);
printf("%s", dest);
}
void second_try() // works
{
size_t numc = 1;
char dest[24] = "i get overwritten";
char *src = "lone wolf c program\n";
memcpy(dest, src, 20);
printf("%s", dest);
}
int main(void)
{
//first_try(); // run-time error
second_try();
}
Why does the first_try() method cause a segmentation fault error?
Context
// feel free to ignore this context
I'm still a c programming newb. I went to https://www.devdocs.io and looked at the api for memcpy().
My instinct was to immediately write first_try(). I don't understand the difference between the dest variables in each function. Don't they both contain valid address values?
I read in a "strings as pointers" blog that "the character array containing the string must already exist". Apparently, writing just char *dest = "string"; compiles but is less useful than writing char buf[] = "string"; with a follow-up ptr that can be passed around: char *dest = &buf;. I'd like to understand the 'why' in all of this.

In C all literal strings (like your "i ") is really a non-modifiable array containing the characters in the string, plus the null-terminator.
Attempting to modify a literal string leads to undefined behavior.
When you use a pointer for dest
char *dest = "i ";
you make the pointer point to the first element of the three-element array for the string "i ".
When you use it as a destination for memcpy you attempt to modify the contents of this non-modifiable array, leading to undefined behavior and your crash.
This is why you should generally always use const when defining such pointers:
const char *dest = "i ";
When you use an array for the destination, it's allocated in a writable part of the memory for your program and you can modify it as you please.
But please make sure the destination array is large enough to hold the full source string, including the null-terminator. Otherwise your memcpy call will write out of bounds of the allocated memory, and you will again have undefined behavior.

Related

C string assignment gives segmentation fault [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 7 years ago.
I am new to C and I want perform this task: declare and initialize a string and then reassign each string element to a new value.
Writing the code in this way:
char *str = "geeksforgeeks\0";
for (int i = 0; str[i] != '\0'; ++i) {
str[i] = 'a';
}
throws a segmentation fault.
But if I write the code in this manner:
char string[] = "geeksforgeeks\0";
char *str = string;
for (int i = 0; str[i] != '\0'; ++i) {
str[i] = 'a';
}
the program behaves correctly.
Also this code:
char str[] = "geeksforgeeks\0";
for (int i = 0; str[i] != '\0'; ++i) {
str[i] = 'a';
}
behaves correctly.
What is the difference between the two? Should't be equivalent?
char *str = "geeksforgeeks\0";
This string is allocated in readonly* memory and you can't modify it. Also the null terminator there is redundant.
Same is not the case with the array you defined, that is why it works. In the case with array the string literal is copied to memory where array resides - and you can modify contents of that array. So using this
char *str = string;
you point to the first element of the array - which as mentioned, is modifiable (as well as all elements of the array).
*It can be they are stored not in read only memory, depends on platform. But anyway you are not allowed to modify them.
If you have:
char *str = "geeksforgeeks\0";
the string is (usually) stored in read-only memory and you get a segmentation fault when you try to modify it. (The \0 is really not needed; you have two null bytes at the end of the string.)
The simplest fix is to use an array instead of a constant string (which is basically what you do in the second working case):
char str[] = "geeksforgeeks";
Note that you should really use this for the string since the string is not modifiable:
const char *str = "geeksforgeeks";
The reason is simple.
In first example, you have a pointer to an static string. that's why you get a segmentation fault.
char *str = "Test";
This is practically a constant string. But in 2nd example, it is a variable that you change.
// You have a variable here
char str_array[] = "Test";
// Now you have a pointer to str_array
char *str = str_array;
You’ve hit on a bit of ugly legacy baggage. When you write the literal "geeksforgeeks\0", the compiler turns that into a pointer to an array of characters. If you later use the string "geeksforgeeks\0" again, it’s allowed to point both references to the same array. This only works if you can’t modify the array; otherwise, fputs(stdout, "geeksforgeeks\0"); would be printing aeeksforgeeks. (Fortran can top this: on at least one compiler, you could pass the constant 1 by name to a function, set it equal to -1, and all your loops would then run backwards.) On the other hand, the C standard doesn’t say that modifying string literals won’t work, and there’s some old code that did. It’s undefined behavior.
When you allocate an array to hold the string, you’re creating a unique copy, and that can be modified without causing errors elsewhere.
So why aren’t string literals const char * instead of char *? Early versions of C didn’t have the const keyword, and the standards committee didn’t want to break that much old code. However, you can and should declare pointers to string literals as const char* s = "geeksforgeeks\0"; so the compiler will stop you from shooting yourself in the foot.

Bus error 10 in C: string literals [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 7 years ago.
Can someone explain why
char *s1 = "abcd";
char *s2 = s1;
s1[0] = "z";
s1[2] = "\0";
gives me a bus error 10 BUT
char s1[] = "abcd";
char *s2 = s1;
s1[0] = "z";
s1[2] = "\0";
doesn't?
are char *s1 and char s1[] not equivalent? Please explain, thanks.
Be free (of historical lazyness), be wise! Pointers are not arrays! Tutorials have lied you!
In the first example, you're modifying a pointer to a constant string literal, and that's undefined behaviour. Anything can happen then!
Meanwhile, in the second case, the string itself is stored inside the array, and the array itself is in the stack. Thus, the second example exposes more than a plain innocent array that's modifiable.
The s2 pointers make no difference in all this. IMHO, the fact that the first case is compilable is just historical lazyness, otherwise known as backwards compatibility.
BTW: Are you assigning string literals to chars? That's undefined behaviour too!
In the first case you set a s1 pointer to the address const string. Const string are stored in read -only area and you cannot modify it. This means that you cannot modify a character s[x]. It is UB
In the second case you declare a local array inited with a string. In this case only the init value is read-only and after init you use an allocated array that can be modified.

Segmentation Fault while using tolower() on dynamic arrays [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 8 years ago.
I put this code on my C compiler (Dev Cpp).
char *str = "SomeTHing";
for(int i = 0; str[i]; i++){
str[i] = tolower(str[i]);
}
This gives a segmentation fault whereas if i use a static array,
char str[10] = "SomeTHing";
the loop works fine. Can anyone tell why is this happening?
char *str = "SomeTHing"; allocates read-only memory to the pointer str. To change its contents in any way is undefined behaviour. On your system that is manifesting itself as a crash. It's a pity that (i) your compiler is not warning you about your assigning this to a char* rather than a const char* or (ii) you're ignoring the warning.
char str[10] = "SomeTHing"; allocates the buffer on the stack, including the null terminator. Changing its contents is defined, although you need to keep a null terminator intact if you want to use some of the string library functions like strlen that rely on it.
char *str = "SomeTHing";
will place SomeTHing in the read-only parts of the memory and making str a pointer to that, making any writing operation on this memory illegal. Any try to modification this cause Undefined Behaviour.
Now following case
char str[10] = "SomeTHing";
this is working because puts the literal string in read-only memory and copies the string to newly allocated memory on the stack. it will probably be stored within an "initialized data segment" that is loaded from the executable file into write able memory when the program is run.

Segmentation Fault related to Pointer in c [duplicate]

This question already has answers here:
Segmentation fault with strcpy() [duplicate]
(7 answers)
Closed 9 years ago.
int main()
{
char *s="Hello";
*s="World";
printf("%s\n",s);
}
Why does the above program result in a segmentation fault?
int main()
{
char *s="Hello"; // makes 's' point to a constant
*s="World"; // modifies what 's' points to
printf("%s\n",s);
}
The first line of code makes s point to a constant. The second line tries to modify what s points to. So you are trying to modify a constant, which you can't do because a constant is ... well ... constant.
because *s is a char not a char*(string)
char *s="Hello";
declares a pointer to a string literal "Hello". This may exist in read-only memory so the line
*s="World";
is results in undefined behaviour. A crash is a valid (and useful) form of undefined behaviour.
Either of the following alternatives would work
const char* s = "Hello";
s="World";
printf("%s\n",s);
char s[16] = "Hello";
strcpy(s, "World";)
printf("%s\n",s);
s points to static (global) memory when it is created. You cannot reassign to that memory at run-time, hence, the crash.
*s is the first char of the string, so assigning string to character makes error.
If you want to assing string use s = "world"
int main()
{
char *s="Hello";
s="World";
printf("%s\n",s);
}
now try it will work.
char *s="hello"; Here s is in readonly location. So we can assign another string, but cannot rewrite new string.
s = "hello"; //work
strcpy(s, "hello"); //segmentation fault
There are two problems here.
The statement
*s = "World";
dereferences s, which gives you the first character of the string "Hello", or 'H'. So you're trying to assign a pointer value (the address of the string "World") to a single char object (the first character of the "Hello" string literal).
But...
On some systems (such as yours, apparently), string literals are stored in a read-only data segment, and attempting to modify read-only memory will lead to a runtime error on some systems. Hence the crash.
To change s to point to the "World" string literal, simply drop the dereference:
s = "World";
*s is the same as s[0]. s[0] has room to store a single character; in this case a 'W'.
There's not room to store the location of "World" in that character.
That's why you're getting a segmentation fault.

Segmentation Fault ++operator on char * [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why does this Seg Fault?
I receive a segmentation fault when using ++ operator on a char *
#include<stdio.h>
int main()
{
char *s = "hello";
printf("%c ", ++(*s));
return 0;
}
But if I do the following:
#include<stdio.h>
int main()
{
char *s = "hello";
char c = *s;
printf("%c ", ++c);
return 0;
}
Then the code compiles perfectly, what is the problem with the above code?
The first code snippet is attempting to modify a character in a string literal as:
++(*s)
is attempting to increment the first character in s. String literals are (commonly) read-only and an attempt to modify will cause the segmentation fault (the C standard states If the program attempts to modify such an array, the behavior is undefined.).
The second snippet is modifying a char variable, which is not read-only as after:
char c = *s;
c is a copy of the first character in s and c can be safely incremented.
In the first case you modify a constant literal, and in the second you modify a variable.
This code:
printf("%c ", ++(*s));
tries to modify a string literal through a pointer to one of its characters. Modifying string literals is undefined behavior - the quite likely outcome is that string literals are often stored in read-only memory, so it's technically illegal to modify them and that's why it manifests itself as segmentation fault on your system.
char *s = "hello";
This implies that 's' is a const string.
If you need a non-const string, you should allocate it explicitly from heap.
You are trying to change a string literal in the first case which is not allowed. In the second case you create a new char from the first character of the string literal. You modify the copy of that character and that is why the second case works.
Your code does not have write permission for the segment where the string literal is stored.

Resources