2015-06-25 4 views
-1

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

Мой код:

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#define BUFFSZ 20 
int main() 
{ 
     char *name = NULL; 
     char my_name[BUFFSZ] ; 
     memset(my_name,0,BUFFSZ); 
     strcpy(my_name, "vinothkumarsaradavallivaradathirupathi"); 
     printf("string copied is %s\n",my_name); 
     if ((name = malloc(1 + strlen(my_name)+1)) != NULL) 
       strcpy(name,my_name); 
     printf("Name is %s\n",name); 
     free(name); 
     name = NULL; 
     return 0; 
} 

Фактический выход:

string copied is vinothkumarsaradavallivaradathirupathi 
Name is vinothkumarsaradavalliva�� 

Согласно кодексу, я ожидал, что ниже выход, но получил только один выше. Это будет полезно, если кто-то объяснит это четко.

Ожидаемый результат:

string copied is vinothkumarsaradaval 
Name is vinothkumarsaradaval 

Когда я запустил этот код в GDB, я получил следующий вывод:

Breakpoint 2, main() at first_pgm.c:12 
12    memset(my_name,0,BUFFSZ); 
(gdb) n 
14    strcpy(my_name, "vinothkumarsaradavallivaradathirupathi"); 
(gdb) p name 
$1 = 0x0 
(gdb) p my_name 
$2 = '\000' <repeats 19 times> 
(gdb) n 

Breakpoint 3, main() at first_pgm.c:15 
15    printf("string copied is %s\n",my_name); 
(gdb) p my_name 
$3 = "vinothkumarsaradaval" 
(gdb) n 
string copied is vinothkumarsaradavallivaradathirupathi 

Вот почему "$ 3" и "строка копируется" выходы конфликтуют ?

+2

Вы знаете, что копируете 39 байт в массив из 20 элементов? –

+0

Да, я намеренно запрограммирован на понимание управления памятью –

+3

Почему это поможет вам понять управление памятью? Это просто вызывает поведение undefind, поэтому оно не будет последовательным и, как таковое, не полезно для обучения. –

ответ

1

Вы копируете 19 байтов больше, чем разрешено, что вызывает неопределенное поведение. Поскольку ваш массив может хранить только 20 символов, но вы копируете 39.

Просто измените

#define BUFSIZE 39 

и он будет работать.

Кроме того, этот

if (NULL != (name = (char *)malloc(sizeof(char)*(strlen(my_name)+1)))) 

является extreamly некрасиво,

  1. Не отвергни возвращаемое значение malloc() которое void * и преобразуется в любой другой тип указателя без литья.
  2. Не используйте sizeof(char), потому что это по определению.

Закрепление код это будет выглядеть

if ((name = malloc(1 + strlen(my_name))) != NULL) 

И вы проверяете для NULL, но вы по-прежнему делать это

printf("Name is %s\n", name) 

это вызовет undedfined поведение в случае name == NULL.

+0

полезный, как всегда, +1. :-) –

+0

Очки №2 и №3 имеют прочные технические обоснования, но условия Йоды - это вопрос мнения. Мне они не нравятся, но высказывание мнения в этих абсолютных терминах может заставить людей с меньшей вероятностью прислушаться к остальным вашим советам (что хорошо, кстати). – trentcl

+0

Удалены условия йоды и изменены коды в соответствии с рекомендациями по ур. –

2

Ожидаемый результат

Подождите. Вы не можете получить ожидаемый результат этого кода. Этот код производит undefined behavior.

В коде

strcpy(my_name, "vinothkumarsaradavallivaradathirupathi") 

вы накат выделенной памяти. В вашем случае my_name не хватает памяти для хранения полного содержимого литерала исходной строки.

Результат: неопределенное поведение.

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

Это говорит,

  1. Do not cast возвращаемое значение malloc() и семьи.

  2. Рекомендованный (скорее, требуется) подпись main() является int main(void), когда вы не намерены использовать любые аргументы командной строки.

+0

Это фактически подпись [_required_] (http://port70.net/~nsz/c/c11/n1570.html#5.1.2.2.1p1), а не только рекомендованная. – Olaf

+0

@Olaf Я использовал _ «рекомендуется» _, чтобы оставить пространство для _ «реализации, определенной образом» _ part. Надеюсь, я не ошибаюсь. :-) –

+0

Ну, для размещенных сред на самом деле нет свободного места. А для фристайна нет никакой рекомендации. Итак: я ценю, что вы осторожны с абсолютными заявлениями, но на этот раз: просто сделайте это, будь храбрым! ;-)) – Olaf

0

Это классический переполнение буфера. strcpy не прекратит записывать символы в буфер назначения до тех пор, пока не найдет завершающий символ '\0'. Память, в которую он записывается, определяется реализацией, поэтому вы не можете надежно ее прочитать. Используйте strncpy, чтобы установить потолок на количество данных. strcpy скопирует.

+0

Да, я понял. Но когда я запускаю GDB, я получил что-то вроде ниже –

+0

Breakpoint 2, main() at first_pgm.c: 12 12 memset (my_name, 0, BUFFSZ); (gdb) n 14 strcpy (my_name, "vinothkumarsaradavallivaradathirupathi"); (GDB) р имя $ 1 = 0x0 (GDB) р my_name $ 2 = '\ 000' <повторяется 19 раз> (Gdb) N точки останова 3, основная() в first_pgm.c: 15 15 PRINTF («string copyed is% s \ n», my_name); (gdb) p my_name $ 3 = "vinothkumarsaradaval" –

+0

Отладчик, зная, что только 20 символов являются частью переменной my_name, отображает только много, независимо от того, сколько strcpy написано. –

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