Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Can't we copy a string to Character Pointer WHEN we can assign a string directly to it?

Tags:

c

pointers

This code produces "p = hello world":

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

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

But this code produces a segmentation fault:

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

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

and this code produces "p = hello"

#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;

}

like image 291
aks Avatar asked Feb 08 '10 15:02

aks


People also ask

Can we copy a string to a pointer?

Using the inbuilt function strcpy() from string. h header file to copy one string to the other. strcpy() accepts a pointer to the destination array and source array as a parameter and after copying it returns a pointer to the destination string.

How do I copy a string into a char pointer?

Syntax: char* strcpy (char* destination, const char* source); The strcpy() function is used to copy strings. It copies string pointed to by source into the destination . This function accepts two arguments of type pointer to char or array of characters and returns a pointer to the first string i.e destination .

Can I assign string to char pointer?

When you say char str2 [] = "Hello" , you are creating a string literal and putting it in the array during its definition. It is ok to not give a size, as the array calculates it and appends a '\0' to it. You cannot reassign anything to that array without resizing it. That is why str2 = "four" will not work.

Can a character pointer store a string?

Instead of using arrays, we can use character pointers to store a string value.


7 Answers

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.

like image 160
jschmier Avatar answered Oct 02 '22 02:10

jschmier


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.

like image 35
danben Avatar answered Oct 02 '22 02:10

danben


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

like image 20
jldupont Avatar answered Oct 02 '22 01:10

jldupont


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.

like image 23
Nikolai Fetissov Avatar answered Oct 02 '22 01:10

Nikolai Fetissov


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.

like image 39
caf Avatar answered Oct 02 '22 02:10

caf


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

like image 35
Phillip Ngan Avatar answered Oct 02 '22 02:10

Phillip Ngan


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

char *p = strdup("hello");
printf("p is %s \n",p);
like image 23
joveha Avatar answered Oct 02 '22 01:10

joveha