I have the following bit of code:
#include <stdio.h>
int main(){
char *p = "abc";
char c = *p;
printf(&c);
return 0;
}
Running, I get
[OP#localhost test]$ gcc ptr.c
[OP#localhost test]$ ./a.out
a%QV[OP#localhost test]$
I was expecting it to just print "abc". Why does this happen?
char c = *p; this does a hard copy of the first letter in the string "abc", nothing else.
Therefore you end up lying to printf and tell it that at the address of the single character c, it will find a whole, valid format string.
But it will only find the character a which is not a string at all, since there is no null terminator anywhere. So anything can happen, including a program crash or the program printing garbage.
The format string is expected to be a NUL-terminated sequence of characters.
printf(p) works because
*(p+0) is 61
*(p+1) is 62
*(p+2) is 63
*(p+3) is 0
printf(&c) doesn't work because
*(&c+0) is 61
*(&c+1) is {Undefined behaviour to access}
Solution 1:
char *p = "abc";
char c = *p;
printf("%c". c); // a
Solution 2:
char *p = "abc";
char *p2 = *p; // Copies the pointer
printf(p2); // abc
Solution 3:
char *p = "abc";
char *p2 = strdup(p); // Copies the string (e.g. so you could modify it)
printf(p2); // abc
free(p2);
Tip: Unless you can guarantee a lack of %, printf(p) is usually wrong. Use printf("%s", p).
Related
I am a beginner of c. Today when i write a c program, I find some strange thing.
What i want it to show is abc, but it show abcefg. I want to know why it's so shown.
the code is:
#include <stdio.h>
int main() {
char a[3] = "abc";
char b[3] = "efg";
printf("%s", a);
return 0;
}
It's answer is not abc but abcefg
Strings in C are zero terminated with '\0'. "abc" actually is { 'a', 'b', 'c', '\0' }, which is 4 chars. Your array a only has room for 3 chars so the '\0' isn't stored. When printf() tries to print the string stored in a it reads and prints one character a time until it encounters a terminating '\0', but there is none. So it continues reading and printing. And it happens that b is right next to a in memory, so the content of b gets printet as well.
Cure:
#include <stdio.h>
int main(void)
{
char a[4] = "abc";
char b[4] = "efg";
printf("%s", a);
}
or, even better, don't specify a size for the arrays at all. Let the compiler figure out the correct size based on the initializer "abc":
#include <stdio.h>
int main(void)
{
char a[] = "abc";
char b[] = "efg";
printf("%s", a);
}
char a[3] = "abc"; misses space for the 0-terminator, so printf will read out of bounds (undefined behavior) into the next memory location , where it finds the b array (by luck).
You should use char a[4] = "abc"; or char a[] = "abc";.
When you do not write an array size, the compiler will evaluate the minimum size from the initialization.
char b[3] = "efg"; has the same problem, but it seems that you are lucky enough to have a 0 byte afterwards.
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?
I am new in C. I am referring to the book "The C Programming Language" by Brian W Kernighian and Dennis Ritchie.
There is a code for pointer increment and assignment given in the book as follows.
#include<stdio.h>
int main()
{
char *s = "Goal";
char *t = "Home";
while(*s++ = *t++) printf(*s);
return 0;
}
The code is saved and compiled using the command
gcc ptr.c -o ptr -std=c99
Now on running the code by running command
./ptr
I get the following error
Segmentation fault (core dumped)
The error seems to be inside the while loop condition.
But the code is exactly as given in the book.
What am I missing?
s and t are both string literals, and you can't modify a string literal. But this piece of code
*s++ = *t++
will modify s, which causes segmentation fault.
To fix it, use a char array. I also modified the printf part to make it legal.
#include<stdio.h>
int main()
{
char arr[] = "Goal";
char *s = arr;
char *t = "Home";
while(*s++ = *t++)
;
printf("%s\n", arr);
return 0;
}
However, I think this program is better done using an individual function to copy the string, the program will look clearer.
#include<stdio.h>
void my_strcpy(char *s, char *t);
int main()
{
char s[] = "Goal";
char *t = "Home";
my_strcpy(s, t);
printf("%s\n", s);
return 0;
}
void my_strcpy(char *s, char *t)
{
while(*s++ = *t++)
;
}
The problem is that printf expects the first parameter to be a char *, that is, something that points to a character, or the address of a character. When you say printf(*s) you're passing it an actual character, i.e. a number from 0 to 255 or -128 to 127, and the program is going to treat that number as an address, which isn't going to be a valid address on your system.
When ever we say *s = "hello" , s is pointing to an address which is present in text segment("hello" goes into text segment). So obviously changing the value of text segment results in SEGV termination.
And for s[] = "hello" if we do *s++, we are incrementing (modifying) the base address so we got "lvalue required as increment operand" error.
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;
}
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;
}