Правильное использование / создание динамических cstrings в C с помощью malloc?
Следующий код всегда segfaults:
char *test3 = (char *) malloc(sizeof(char) * 5);
test3 = "asdf";
printf("%sn", test3);
Следующий код не сегментируется:
char *test3 = (char *) malloc(sizeof(char) * 5);
test3[0] = 'a';
test3[1] = 'b';
test3[2] = 'c';
test3[3] = 'd';
test3[4] = '';
printf("%sn", test3);
Я предполагаю, что вопрос может заключаться в том, как мне назначить литерал cstring динамически создаваемому cstring?
4 ответа:
Правильный способ "заполнить" строку:
strcpy(test3, "abcd");
Однако я настоятельно рекомендую вам не использовать
malloc
[и определенно не использовать(char *) malloc(...)
- поскольку это может скрыть некоторые довольно неприятные ошибки, которые подпрыгивают и кусают вас, по крайней мере, в подходящий момент, поскольку ошибки имеют тенденцию делать это - вы, вероятно, делаете это, потому что вы компилируете свой C-код как C++-код, что неправильно и учит вас плохим привычкам, таким как эта].Использование
malloc
для выделения маленьких строк является большим пустая трата пространства. Ваша строка из 5 символов, вероятно, имеет накладные расходы в размере 16-32 байт и будет округлена до 8 или 16 байт. Таким образом, в общей сложности он может использовать 48 байт, хранить 5 байт - это большая потеря пространства.
Другие (правильно) предложили скопировать строку в выделенную память.
Вот почему ваш подход является segfaulting: строка "asdf" является строковым литералом, и во время компиляции она сохраняется в rodata, или только для чтения данных. Когда ваша программа пытается
test3 = "asdf";
Он пытается создать указатель на rodata. C не допускает указателей в rodata, и поэтому ваше утверждение не только не работает, но и seg ошибается.
Второй метод был хорош, потому что вы не изменяете указатель, но скорее то, на что он указывает.
Во-первых, спасибо за этот вопрос у него есть интересная морщинка.
Я запустил ваш код с Eclipse / Microsoft C и не получил ошибки сегментации, и он напечатал "asdf", как ожидалось.
Однако это не означает и не подразумевает, что вы не получаете ошибки сегментации. Ваш результат подразумевает рассмотрение того, как компилятор реализует два оператора:char *test3 = (char *) malloc(sizeof(char) * 5);
Выделяет хранилище в куче и устанавливает указатель
test3
, чтобы указать на это место. Следующий оператор также обновляет тот же указатель.test3 = "asdf";
Однако в этом случае
test3
указывает на литерал "asdf", где-либо этот литерал хранится. Некоторые компиляторы генерируют пул литералов строк и хранят их где-то в исполняемом файле, поэтому для некоторых компиляторов эти литералы не могут быть изменены.Так зачем компилятору хранить литерал там, где к нему нельзя получить доступ? Не имеет смысла, отсюда вопрос: какой компилятор Си вы используете? И что это за версия с придерживаясь??
Чтобы обойти то, что может быть ошибкой компилятора, и все же указать
test3
на литерал, попробуйте?? (Опять же, компиляторы C различаются тем, что и как они реализуют языковые конструкции.)Наконец, во втором примере хранилище в куче, которое былоconst char *literal = "asdf"; // also try without a const stmt // other code here test3 = literal;
malloc
ed, модифицируется и, очевидно, адресуемо.
Вы не можете назначить строковое значение с " = " в вашем случае.
Вам нужно использовать функцию strcpy или sprintf. В конце программы (или когда строка больше не используется) не забудьте ее освободить ! Например:
#define BUFSIZE 5 int main(void) { char *test3 = malloc(sizeof(char) * BUFSIZE); snprintf(test3,BUFSIZE,"test"); printf("%s\n", test3); free(test3); return 0; }
Или вы можете просто написать:
int main(void) { char buf[BUFSIZE] = "test"; printf("%s\n", buf); return 0; }