2013-08-07 2 views
3

Следующий код всегда возвращает ошибку сегментации:Правильное использование/создание динамических cstrings в C с malloc?

char *test3 = (char *) malloc(sizeof(char) * 5); 
    test3 = "asdf"; 
    printf("%s\n", test3); 

Следующий код не сегментации:

char *test3 = (char *) malloc(sizeof(char) * 5); 
    test3[0] = 'a'; 
    test3[1] = 'b'; 
    test3[2] = 'c'; 
    test3[3] = 'd'; 
    test3[4] = '\0'; 
    printf("%s\n", test3); 

Я думаю, этот вопрос может быть как я назначить CString буквального динамически созданный CString?

+2

Вы уверены, что первый код-образец правильно скопирован, так как он не выглядит так, как будто он рушится ко мне ... Возможно, в вашем примере вы делали что-то еще, кроме как скопировать константу в 'test3' - например, попробуйте ALTER содержимое 'test3'? Или вы имеете в виду, что он падает, когда вы пытаетесь освободить 'test3'? –

+0

Я удивлен, что вы даже можете сделать первый образец с современными компиляторами и их nixing, позволяющий назначать адреса const неконстантным указателям. Ваш первый образец также пропускает самую память, которую вы выделили в первой строке, путем перезаписи возвращаемого адреса на следующей строке. То есть вы пропустили память в двух коротких строках. Я согласен с Мэттом, вы, вероятно, рушитесь на 'free()' call * после * кода в первом примере, так как вы освобождаете const-память. – WhozCraig

ответ

2

Правильный способ «заполнить» строка:

strcpy(test3, "abcd"); 

Однако, я бы настоятельно рекомендуем вам не использовать malloc [и, безусловно, не используйте (char *) malloc(...) - так что можно скрыть некоторые довольно неприятные ошибки, которые вскакивают и укусывают вас хотя бы на подходящий момент, поскольку у ошибок есть такая тенденция - вы, вероятно, это делаете, потому что вы компилируете свой C-код как код C++, что неправильно, и учит вам вредные привычки как этот].

Использование malloc для выделения небольших струн - большая трата пространства. Вероятно, ваша строка с 5 символами имеет накладные расходы в 16-32 байта и будет округлена до 8 или 16 байт. Таким образом, в общей сложности он может использовать 48 байтов, чтобы сохранить 5 байтов - это большая потеря пространства.

0

Вы не можете назначить строковое значение с «=» в вашем случае.

Вам необходимо использовать функцию 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; 
} 
0

Другие (правильно) предложил скопировать строку в выделенной памяти.

Вот почему ваш подход является segfault: Строка «asdf» является строковым литералом, а во время компиляции она хранится в rodata или только для чтения. Когда ваша программа пробует

test3 = "asdf"; 

Он пытается создать указатель на родата. C не позволяет указателям на родату, и поэтому ваше утверждение не только не работает, но и само по себе.

Второй способ был прекрасен, потому что вы не изменяете указатель, а скорее то, на что оно указывает.

0

Прежде всего, благодарю вас за этот вопрос, у вас есть интересная морщина.

Я запустил ваш код с помощью Eclipse/Microsoft C и НЕ получил ошибку сегментации, и он напечатал «asdf», как ожидалось.

Однако это НЕ означает или подразумевает, что вы не получаете ошибку сегментации. Ваш результат предполагает изучение того, как компилятор реализует два заявления:

char *test3 = (char *) malloc(sizeof(char) * 5); 

Выделяет память в куче и устанавливает указатель, test3, чтобы указать на это место. Следующий оператор также обновляет тот же указатель.

test3 = "asdf"; 

Однако в этом случае test3 указывает на буквальное «Asdf» где-нибудь, что буквальное хранится. Некоторые компиляторы генерируют литеральный пул строк и хранят их где-то в исполняемом файле, поэтому для некоторых компиляторов эти литералы не могут быть изменены.

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

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

const char *literal = "asdf"; // also try without a const stmt 
    // other code here 
    test3 = literal; 

Наконец, во втором примере хранения в куче, которая была malloc ред модифицируется и, очевидно, адресацией.