Strings and manipulating strings , what exactly happens here.? - c

Why am I'm getting this error "Segmentation fault (core dumped)" while running this program, what is wrong with it?
#include <stdio.h>
int main() {
char *p = "Sanfoundry C-Test";
p[0] = 'a';
p[1] = 'b';
printf("%s", p);
return 0;
}

String literals are unmodifiable in C:
char *p = "Sanfoundry C-Test";
p[0] = 'a';
The last statement invokes undefined behavior.
Use a character array initialized with a string literal to have a defined behavior:
char p[] = "Sanfoundry C-Test";
p[0] = 'a';

As others have said, that should not be done that way, since you are modifying something that is supposed to be (and often is) unmodifiable.
char *p = "Sanfoundry C-Test";
This declares a pointer and points it to (sets the address contained in the pointer to the start of) the literal text (which is constant and should not be modified and probably can't be modified without an error anyway) "Sanfoundry C-Test".
But AFAIK, you are asking what the rest of the code means, so let's first correct the problem:
char p[] = "Sanfoundry C-Test";
That declares an array of char with the given contents (the characters 'S', 'a', 'n', etc., followed by a 0 character). Such an array is treated as a text string, by C. Now
p[0] = 'a';
Changes the first character of that array (arrays "start counting" at 0), so the 'S' in the string is changed to an 'a'.
p[1] = 'b';
This changes the second character into 'b'. So now the string is "abnfoundry C-Test". The final printf() then displays that value in a console.

This is the difference between a char array and a char pointer.
char p[]="Sanfoundry C-Test";
Then you can do
p[0]='a';
p[1]='b';
But you cannot do it if p is a pointer which is in your case.
For more information, see the link provided below
What is the difference between char s[] and char *s?

Related

Run-time error in program

int main()
{
char *p="abcd";
while(*p!='\0') ++*p++;
printf("%s",p);
return 0;
}
I am not able to understand why the code does not run. The problem is in the statement ++*p++, but what is the problem?
P points to constant string literal *p="abcd"; by doing ++*p++ you are trying to modify string '"abcd"', for example a in string will be increment to 'b' because of ++*p that is undefined behavior (constant string can't change). it may cause a segmentation fault.
`++*p++` means `++*p` then `p++`
^
| this operation try to modify string constant
char *p="abcd";
p is pointing to a readonly segment and you can not increment p as you did here
while(*p!='\0') ++*p++;
//char *p="abcd";//"string" is const char, don't change.
char str[]="abcd";//is copied, including the '\0' to reserve space
char *p = str;
while(*p!='\0') ++*p++;
//printf("%s",p);//address pointing of 'p' has been changed
printf("%s",str);//display "bcde"
char *foo = "abcd";
char bar[] = "abcd";
Consider the differences between foo and bar. foo is a pointer that's initialised to point to memory reserved for a string literal. bar is an array with it's own memory that's initialised to a string literal; it's value is copied from the string literal during initialisation. It is appropriate to modify bar[0], etc, but not foo[0]. Hence, you need an array declaration.
However, you can't increment an array declaration; That's an operation for pointer variables or integer variables. Additionally, your loop changes where p points at, before it's printed, so you need to keep the original location of your string somewhere. Hence, you also need a pointer, or an integer declaration.
With this in mind, it might seem like a good idea to change your code to something like this:
int main()
{
char str[] = "abcd";
/* Using a pointer variable: */
for (char *ptr = str; *ptr != '\0'; ++*ptr++);
/* Using a size_t variable: */
for (size_t x = 0; str[x] != '\0'; str[x++]++);
printf("%s", str);
return 0;
}

unexpected error on printing string

Why does this code produce an error? Shouldn't it output zbcde?
int main()
{
char *p="abcde";
*p='z';
printf("%s\n",p);
return 0;
}
You're trying to modify a string literal; it's undefined behavior.
Further explanation: "abcde" is not a char * but a const char *. You should do one of the following solutions:
char p[] = "abcde";
or
char *p = strdup("abcde");
(in the latter case, don't forget to free() p!)
char *p="abcde"; - This will keep the string abcde in text segement as read only data and the address will be kept in the local pointer variable p.
*p = 'z' will tries to replace the read only data a to z. Which is an undefined behaviour, which can leads to crash.
So declare the string as local char array variable as below.
char p[] = "abcde"
So allocate dynamic memory to keep the string like below.
char *p = strdup("abcde");
...
free(p);

changing one char in a c string

I am trying to understand why the following code is illegal:
int main ()
{
char *c = "hello";
c[3] = 'g'; // segmentation fault here
return 0;
}
What is the compiler doing when it encounters char *c = "hello";?
The way I understand it, its an automatic array of char, and c is a pointer to the first char. If so, c[3] is like *(c + 3) and I should be able to make the assignment.
Just trying to understand the way the compiler works.
String constants are immutable. You cannot change them, even if you assign them to a char * (so assign them to a const char * so you don't forget).
To go into some more detail, your code is roughly equivalent to:
int main() {
static const char ___internal_string[] = "hello";
char *c = (char *)___internal_string;
c[3] = 'g';
return 0;
}
This ___internal_string is often allocated to a read-only data segment - any attempt to change the data there results in a crash (strictly speaking, other results can happen as well - this is an example of 'undefined behavior'). Due to historical reasons, however, the compiler lets you assign to a char *, giving you the false impression that you can modify it.
Note that if you did this, it would work:
char c[] = "hello";
c[3] = 'g'; // ok
This is because we're initializing a non-const character array. Although the syntax looks similar, it is treated differently by the compiler.
there's a difference between these:
char c[] = "hello";
and
char *c = "hello";
In the first case the compiler allocates space on the stack for 6 bytes (i.e. 5 bytes for "hello" and one for the null-terminator.
In the second case the compiler generates a static const string called "hello" in a global area (aka a string literal, and allocates a pointer on the stack that is initialized to point to that const string.
You cannot modify a const string, and that's why you're getting a segfault.
You can't change the contents of a string literal. You need to make a copy.
#include <string.h>
int main ()
{
char *c = strdup("hello"); // Make a copy of "hello"
c[3] = 'g';
free(c);
return 0;
}

Initializing arrays of type char

I want to initialize arbitrary large strings. It is null terminated string of characters, but I cannot print its content.
Can anybody tell me why?
char* b;
char c;
b = &c;
*b = 'm';
*(b+1) = 'o';
*(b+2) = 'j';
*(b+3) = 'a';
*(b+4) = '\0';
printf("%s\n", *b);
Your solution invokes undefined behaviour, because *(b+1) etc. are outside the bounds of the stack variable c. So when you write to them, you're writing all over memory that you don't own, which can cause all sorts of corruption. Also, you need to printf("%s\n", b) (printf expects a pointer for %s).
The solution depends on what you want to do. You can initialize a pointer to a string literal:
const char *str1 = "moja";
You can initialize a character array:
char str2[] = "moja";
This can also be written as:
char str2[] = { 'm', 'o', 'j', 'a', '\0' };
Or you can manually assign the values of your string:
char *str3 = malloc(5);
str3[0] = 'm';
str3[1] = 'o';
str3[2] = 'j';
str3[3] = 'a';
str3[4] = '\0';
...
free(str3);
This might result in a segmentation fault! *(b+1), *(b+2) etc refer to unallocated areas. First allocate memory and then write into it!
b doesn't have enough space to hold all those characters. Allocate enough space using malloc or declare b as a char array.
Your code is not safe at all! You allocate only 1 char on the stack with char c; but write 5 chars into it! this will give you a stack-overflow which can be very dangerous.
Another thing: you mustn't dereference the string when printing it: printf("%s\n", b);
Why not simply write const char *b = "mojo";?
You need to assign memory space for it, either with malloc or using a static array. Here, in your code, you're using the address of just one character to store at the addresses of that characters, and others following it. This is not defined.
Note, step by step, what you're doing. First, you assign the pointer to point to a single char space in memory. Then, by using *b = 'm' you set that memory to the character 'm'. But then, you access to the next memory position (that is undefined, because no memory is reserved for that position) to store another value. This won't work.
How to do it?
You have two options. For example:
char *b;
char c[5];
b = &c[0];
*b = 'm';
... //rest of your code
This will work because you have space for 5 chars in c. The other option is to directly assign memory for b using malloc:
char * b = (char*) malloc(5);
*b = 'm';
... // rest of your code
Finally, maybe not what you want, but you can either initialize a char array or pointer using a string literal:
char c[] = "hello";
const char* b = "abcdef";
The printf does not print because it expect a char*, so you should pass b, not *b.
To initialize a pointer to a string constant you can do something like:
char *s1 = "A string"
or
char s2[] = "Another string"
or allocate a buffer with char *b = malloc(5) and then write to this buffer (as you did, or with the string functions)
what you did was taking the address of a single char memory location and then write past to it, possibly overwriting other variables or instructions and thus possibly leading to data corruption or crash.
If you write the following instead of your printf, it will print the first character.
printf("%c\n", *b);
In order for you to have arbitrarily large strings, you will need to use a library such as bstring or write one of your own.
This is because, in C one needs to get memory, use it and free it accordingly. b in your case only points to a character unless you allocate memory to it using malloc. And for malloc you have to specify a fixed size.
For arbitrarily large string, you need to encapsulate the actual pointer to character in a data structure of your own, and then manage its size according to the length of the string that is to be set as its value.
printf("%s\n", *b);
why *?
printf("%s\n", b);
is what you want

Why does *(str+i) = *(str +j) not work here?

void reverse(char *str){
int i,j;
char temp;
for(i=0,j=strlen(str)-1; i<j; i++, j--){
temp = *(str + i);
*(str + i) = *(str + j);
*(str + j) = temp;
printf("%c",*(str + j));
}
}
int main (int argc, char const *argv[])
{
char *str = "Shiv";
reverse(str);
printf("%s",str);
return 0;
}
When I use char *str = "Shiv" the lines in the swapping part of my reverse function i.e str[i]=str[j] dont seem to work, however if I declare str as char str[] = "Shiv", the swapping part works? What is the reason for this. I was a bit puzzled by the behavior, I kept getting the message "Bus error" when I tried to run the program.
When you use char *str = "Shiv";, you don't own the memory pointed to, and you're not allowed to write to it. The actual bytes for the string could be a constant inside the program's code.
When you use char str[] = "Shiv";, the 4(+1) char bytes and the array itself are on your stack, and you're allowed to write to them as much as you please.
The char *str = "Shiv" gets a pointer to a string constant, which may be loaded into a protected area of memory (e.g. part of the executable code) that is read only.
char *str = "Shiv";
This should be :
const char *str = "Shiv";
And now you'll have an error ;)
Try
int main (int argc, char const *argv[])
{
char *str = malloc(5*sizeof(char)); //4 chars + '\0'
strcpy(str,"Shiv");
reverse(str);
printf("%s",str);
free(str); //Not needed for such a small example, but to illustrate
return 0;
}
instead. That will get you read/write memory when using pointers. Using [] notation allocates space in the stack directly, but using const pointers doesn't.
String literals are non-modifiable objects in both C and C++. An attempt to modify a string literal always results in undefined behavior. This is exactly what you observe when you get your "Bus error" with
char *str = "Shiv";
variant. In this case your 'reverse' function will make an attempt to modify a string literal. Thus, the behavior is undefined.
The
char str[] = "Shiv";
variant will create a copy of the string literal in a modifiable array 'str', and then 'reverse' will operate on that copy. This will work fine.
P.S. Don't create non-const-qualified pointers to string literals. You first variant should have been
const char *str = "Shiv";
(note the extra 'const').
String literals (your "Shiv") are not modifiable.
You assign to a pointer the address of such a string literal, then you try to change the contents of the string literal by dereferencing the pointer value. That's a big NO-NO.
Declare str as an array instead:
char str[] = "Shiv";
This creates str as an array of 5 characters and copies the characters 'S', 'h', 'i', 'v' and '\0' to str[0], str[1], ..., str[4]. The values in each element of str are modifiable.
When I want to use a pointer to a string literal, I usually declare it const. That way, the compiler can help me by issuing a message when my code wants to change the contents of a string literal
const char *str = "Shiv";
Imagine you could do the same with integers.
/* Just having fun, this is not C! */
int *ptr = &5; /* address of 5 */
*ptr = 42; /* change 5 to 42 */
printf("5 + 1 is %d\n", *(&5) + 1); /* 6? or 43? :) */
Quote from the Standard:
6.4.5 String literals
...
6 ... If the program attempts to modify such an array [a string literal], the behavior is undefined.
char *str is a pointer / reference to a block of characters (the string). But its sitting somewhere in a block of memory so you cannot just assign it like that.
Interesting that I've never noticed this. I was able to replicate this condition in VS2008 C++.
Typically, it is a bad idea to do in-place modification of constants.
In any case, this post explains this situation pretty clearly.
The first (char[]) is local data you can edit
(since the array is local data).
The second (char *) is a local pointer to
global, static (constant) data. You
are not allowed to modify constant
data.
If you have GNU C, you can compile
with -fwritable-strings to keep the
global string from being made
constant, but this is not recommended.

Resources