tags:

views:

143

answers:

7
#include "stdio.h"
#include "string.h"

int main()
{
char *p;
p="hello world";
printf("p is %s \n",p);
return 0;
}

OUTPUT (on Intel PC): p is hello world

#include "stdio.h"
#include "string.h"

int main()
{ 
char *p;
strcpy(p,"hello");
printf("p is %s \n",p);
return 0;
}

OUTPUT (on Intel PC): Segmentation fault (core dumped)

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

int main()
{
char *p;
p=(char*)malloc (10);
strcpy(p,"hello");
printf("p is %s \n",p);
return 0;
}

OUTPUT (on Intel PC): p is hello

+5  A: 

In the case where p="hello world"; (1st case at the time of this edit), p is being initialized to point to a read-only memory region which contains the string "hello world" (string literal). This read-only memory region is created at compile time.

In the case that causes the segmentation fault (2nd case at the time of this edit), p is uninitialized and copying anything to it will produce unpredictable results because the location in memory that p is pointing to is not specified by the code.

Before you can copy a string to p, you must specify the memory that p is pointing to.

You can allocate this memory on the stack

char buf[BUFSIZ] = ""; /* local variable */

on the heap

char *buf = malloc(BUFSIZ); /* don't forget to free */

or in the __DATA segment.

static char buf[BUFSIZ] = ""; /* global variable */

You can then initialize p to point at the memory buffer.

char *p = buf;

This is similar in concept to initializing p to point to the string literal in read-only memory. Unlike the case where p points to the string literal, you can now copy a string to the character pointer as it does not point to read-only memory.

Note: I intentionally created a separate buffer and initialized p to point to it to help make my point.

jschmier
Then, why would this work? #include <stdio.h> #include <string.h> int main() { char *p; p="hello world"; printf("p is %s \n",p); return 0; }<b>Output:</b> p is hello world
aks
You aren't coping anything to p in the first one. You're assigning the address of that string literal to p. That's why it works.
yodaj007
By assigning the address of the string literal to p, you are specifying the location in memory that p is pointing to.
jschmier
**Note:** I updated my answer due to changes in the question.
jschmier
+2  A: 

There is no free lunch - you need to grab & manage memory. If you just assume that because you have access to a pointer memory should be there then you'll run into unspecified behavior (segfault likely).

jldupont
+4  A: 

The reason is that when you declare a pointer, it doesn't actually point to anything useful. strcpy requires a block of memory for the string to be copied into. It will not do this for you automatically.

From the documentation (emphasis mine):

Copies the C string pointed by source into the array pointed by destination, including the terminating null character.

To avoid overflows, the size of the array pointed by destination shall be long enough to contain the same C string as source (including the terminating null character), and should not overlap in memory with source.

You need to make this true, as it is a precondition of the function.

Also, in the parameters section:

destination

Pointer to the destination array where the content is to be copied.

You need to make sure destination is a pointer to an array.

danben
"when you declare a pointer, it doesn't actually point to anything - just NULL" Actually it could point anywhere. Uninitialized does not mean 0.
sepp2k
@sepp2k: Thanks, it's been a while since I've coded any C/C++. Fixed.
danben
+1  A: 

Because in the first example the pointer p contains some random garbage that happens to be on the stack at the time, might be zero, might be anything else, so it points to ... nobody knows where, your code segment, for example. The OS does the right thing and tells you that you are breaking the rules and trying to write to memory that doesn't belong to you. Read the fine description of segmentation faults here.

If you absolutely want to avoid dynamic memory allocation and you know the size of the source string at compile time you can grab appropriate stack space like this:

char buffer[6]; /* strlen( "hello" ) + 1 for zero terminator */
strcpy( buffer, "hello" );

But that is a dangerous road leading to buffer overruns.

Nikolai N Fetissov
+1  A: 

There are two distinct parts to memory copying. The first is the memory occupied by the item you want to copy (which you create in your example using the malloc() function), and the second is a pointer to that block of memory (which you call p). These two entities must be set up for the destination too, before you can do a copy. In your first example that fails, you have not set up the memory block for the destination (but it has been set for the source implicitly when you declare the string hello).

Phillip Ngan
A: 

Yes its annoying. You can use strdup to shorten it:

char *p = strdup("hello");
printf("p is %s \n",p);
joveha
+1  A: 

Notice what the two working examples have in common: they have a p = line that assigns something to p. The non-working example does not do this.

Consider this line (from the first example):

p = "hello world";

Although it might look like it's "copying a string to a char pointer", it's not. It's copying the location of a string to a pointer-to-char. That's what a pointer-to-char like p stores - the location of a contiguous block of chars.

Similarly, consider this line from the third example:

p = malloc(10);

This is also copying a location - it's copying the location of a block of 10 unintialised chars into p.

strcpy(dest, source) copies characters from the location given by source to the location given by dest. It should be clear that if you never set p to a valid location, then strcpy(p, "hello") can't do anything sensible - in your second example, p is an essentially random location, and you then ask strcpy() to copy something to that location.

caf