2010-02-08 4 views
5

Этот код выдает "р = привет мир":Почему мы не можем скопировать строку в Charator Pointer КОГДА мы можем назначить строку непосредственно ей?

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

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

Но этот код выдает ошибку сегментации:

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

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

и этот код выдает "р = 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; 

}

ответ

10

В случае, если p="hello world"; (1-й случай при t он время этого редактирования), p инициализируется, чтобы указывать на область памяти только для чтения, которая содержит строку «hello world» (строковый литерал). Эта область только для чтения область памяти создается во время компиляции.

В случае, который вызывает ошибку сегментации (второй случай во время этого редактирования), p не инициализирован и копирование ничего к нему приведут к непредсказуемым результатам, так как место в памяти, что p указывает на не задать с помощью код.

Прежде чем вы сможете скопировать строку в p, вы должны указать память, на которую указывает p.

Можно выделить эту память на стеке

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

на куче

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

или в сегменте __DATA.

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

Вы можете инициализировать p указывать на буфер памяти.

char *p = buf;

Это похоже на концепции инициализации p, чтобы указать на строку буквального в только для чтения памяти. В отличие от случая, когда p указывает на строковый литерал, теперь вы можете скопировать строку в указатель символа, поскольку она не указывает на только для чтения.

Примечание: Я намеренно создал отдельный буфер и инициализировал p, чтобы указать на это, чтобы помочь сделать мою мысль.

+0

Тогда зачем это работает? #include #include INT Основной() { символ * р; p = "hello world"; printf ("p is% s \ n", p); return 0; } Выход: p hello world – aks

+3

Вы не справляетесь ни с чем с p в первом. Вы назначаете адрес этого строкового литерала на p. Вот почему это работает. – Amy

+0

Назначив адрес строкового литерала p, вы указываете местоположение в памяти, на которое указывает p. – jschmier

2

Нет бесплатного обеда - вам необходимо захватить & управлять памятью. Если вы просто предположите, что, поскольку у вас есть доступ к памяти указателя, он должен находиться в неопределенном поведении (вероятно, segfault).

5

Причина в том, что, когда вы объявляете указатель, на самом деле это не указывает на что-либо полезное. strcpy требует блок памяти для строки, в которую нужно скопировать. Он не будет делать это автоматически.

Из документации (курсив):

Копии строка C указываемого источника в массив, на который указывает место назначения, включая завершающий нуль характер.

Чтобы избежать переполнения, размер массива, на который указывает место назначения должно быть достаточно долго, чтобы содержать один и тот же C строку в качестве источника (в том числе завершающего нулевого символа) и не должны перекрываться в памяти с источник.

Вы должны сделать это правдой, поскольку это является предварительным условием функции.

Кроме того, в разделе Параметры:

назначения

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

Вы должны убедиться, что destination является указателем на массив.

+4

", когда вы объявляете указатель, на самом деле он не указывает ни на что - просто NULL. Фактически он может указывать в любом месте. Uninitialized не означает 0. – sepp2k

+0

@ sepp2k: Спасибо, прошло некоторое время, так как я закодировал любой C/C++. Исправлена. – danben

2

Потому что в первом примере указатель p содержит некоторый случайный мусор, который в данный момент находится в стеке, может быть нулем, может быть что-то еще, поэтому он указывает на ... никто не знает, где, ваш сегмент кода , например. ОС делает все правильно и говорит вам, что вы нарушаете правила и пытаетесь записать в память, которая не принадлежит вам. Прочитано the fine description of segmentation faults here.

Если вы абсолютно хотите, чтобы избежать динамического распределения памяти и вы знаете размер исходной строки во время компиляции вы можете получить соответствующее пространство стека, как это:

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

Но это опасно дорога, ведущая к buffer overruns.

1

Существует две отдельные части для копирования памяти. Первая - это память, занятая элементом, который вы хотите скопировать (который вы создаете в своем примере с помощью функции malloc()), а второй - указатель на этот блок памяти (который вы называете p). Эти два объекта также должны быть настроены для адресата, прежде чем вы сможете сделать копию. В вашем первом примере, который сбой, у вас есть , а не, установите блок памяти для адресата (но он был установлен для источника неявно, когда вы объявляете строку hello).

1

Да, его раздражает. Вы можете использовать strdup, чтобы сократить его:

char *p = strdup("hello"); 
printf("p is %s \n",p); 
2

Обратите внимание, что две рабочие примеры имеют общие черты: они имеют p = линию, которая присваивает то p. Нерабочий пример этого не делает.

Рассмотрим эту линию (от первого примера):

p = "hello world"; 

Хотя это может выглядеть это «копирование строки на указатель полукокса», это не так. Он копирует местоположение строку в указатель на символ. Это то, что указатель-к-char, как p магазины - расположение смежного блока char s.

Аналогичным образом, рассматривать эту линию от третьего примера:

p = malloc(10); 

Это также копирование места - это копирование расположения блока 10 unintialised char с в p.

strcpy(dest, source) копирует символы с местоположения, указанного source, на адрес, указанный dest. Должно быть ясно, что если вы никогда не устанавливали p в действительное место, то strcpy(p, "hello") не может ничего сделать разумно - в вашем втором примере p - это случайное местоположение, и затем вы спрашиваете strcpy(), чтобы скопировать что-то в это место.

Смежные вопросы