Инициализация массивов типа char

Я хочу инициализировать произвольные большие строки. Это строка символов с нулевым завершением, но я не могу распечатать ее содержимое. Кто-нибудь может сказать мне, почему?

char* b;
char c;
b = &c;
*b = 'm';
*(b+1) = 'o';
*(b+2) = 'j';
*(b+3) = 'a';
*(b+4) = '\0';
printf("%s\n", *b);

person matcheek    schedule 01.06.2011    source источник
comment
*(b+1) — это память, которой вы не владеете и которой не должны пользоваться.   -  person yehnan    schedule 01.06.2011


Ответы (8)


Ваше решение вызывает неопределенное поведение, поскольку *(b+1) и т. д. находятся за пределами переменной стека c. Поэтому, когда вы пишете им, вы записываете всю память, которая вам не принадлежит, что может привести к разного рода повреждениям. Кроме того, вам нужно printf("%s\n", b) (printf ожидает указатель на %s).

Решение зависит от того, что вы хотите сделать. Вы можете инициализировать указатель на строковый литерал:

const char *str1 = "moja";

Вы можете инициализировать массив символов:

char str2[] = "moja";

Это также можно записать как:

char str2[] = { 'm', 'o', 'j', 'a', '\0' };

Или вы можете вручную присвоить значения вашей строки:

char *str3 = malloc(5);
str3[0] = 'm';
str3[1] = 'o';
str3[2] = 'j';
str3[3] = 'a';
str3[4] = '\0';

...

free(str3);
person Oliver Charlesworth    schedule 01.06.2011
comment
а для printf требуется указатель с %s, поэтому он должен быть b, а не *b. вы также могли бы объяснить ему, почему брать адрес одного символа и писать строку, начинающуюся с этого места в памяти, плохо-плохо-плохо :) - person garph0; 01.06.2011
comment
почти готово :) я бы проголосовал за вас, но я не полностью согласен с объяснением переполнения. - person garph0; 01.06.2011
comment
@garph0: С какой частью ты не согласен? - person Oliver Charlesworth; 01.06.2011
comment
Тот факт, что переполнение c записывает в память, которой вы не владеете. В данном примере c размещается в стеке, поэтому вы, вероятно, закончите перезаписывать другие переменные (или код), которыми владеете. эффекты, в любом случае, обычно коррупционные, я согласен с этим :-) - person garph0; 03.06.2011

Это может привести к ошибке сегментации! *(b+1), *(b+2) и т. д. относятся к незанятым областям. Сначала выделяй память, а потом пиши в нее!

person Pavan Manjunath    schedule 01.06.2011
comment
Также в вашем заявлении printf просто используйте «b» вместо * b для печати строки - person Pavan Manjunath; 01.06.2011

b не хватает места для хранения всех этих символов. Выделите достаточно места, используя malloc, или объявите b массивом char.

person N.R.S.Sowrabh    schedule 01.06.2011

Ваш код вообще небезопасен! Вы выделяете в стеке только 1 символ с помощью char c;, но записываете в него 5 символов! это приведет к переполнению стека, что может быть очень опасно.

Еще одно: вы не должны разыменовывать строку при ее печати: printf("%s\n", b);

Почему бы просто не написать const char *b = "mojo";?

person king_nak    schedule 01.06.2011

Вам нужно выделить для него место в памяти либо с помощью malloc, либо с помощью статического массива. Здесь, в вашем коде, вы используете адрес только одного символа для хранения адресов этих символов, и других, следующих за ним. Это не определено.

Отметьте, шаг за шагом, что вы делаете. Во-первых, вы назначаете указатель на одно символьное пространство в памяти. Затем, используя *b = 'm', вы устанавливаете в этой памяти символ 'm'. Но затем вы получаете доступ к следующей позиции памяти (которая не определена, поскольку для этой позиции не зарезервирована память) для сохранения другого значения. Это не сработает.

Как это сделать?

У вас есть два варианта. Например:

char *b;
char c[5];
b = &c[0];
*b = 'm';
... //rest of your code

Это будет работать, потому что у вас есть место для 5 символов в c. Другой вариант — напрямую выделить память для b с помощью malloc:

char * b = (char*) malloc(5);
*b = 'm';
... // rest of your code

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

char c[] = "hello";
const char* b = "abcdef";
person Diego Sevilla    schedule 01.06.2011
comment
хорошее объяснение, но это неправда, что он не определен: он просто перезапишет что-то еще в стеке, так как c выделено в стеке. тем более проблема с printf другая :) - person garph0; 01.06.2011

printf не печатает, потому что ожидает char*, поэтому вы должны передавать b, а не *b. Чтобы инициализировать указатель на строковую константу, вы можете сделать что-то вроде:

char *s1 = "A string"

or

char s2[] = "Another string"

или выделить буфер с помощью char *b = malloc(5), а затем записать в этот буфер (как вы это сделали, или с помощью строковых функций)

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

person garph0    schedule 01.06.2011


printf("%s\n", *b);

Почему *?

printf("%s\n", b);

это то, что ты хочешь

person Gangnus    schedule 01.06.2011