2017-01-24 3 views
1

Я новичок в программировании на C, и теперь изучаю строки. Мой вопрос: если я выделяю строку, используя malloc (как в коде ниже), является ли символ NULL автоматически вставлен в конце строки? Я нашел ответ в другом вопросе здесь, и кажется, что символ NULL не включается автоматически. Но вот проблема: я знаю, что такие функции, как strlen, не работают, если нет символа NULL, и в этом коде я использую его, и он работает. Поэтому я думаю, что в конце моей строки есть \0, даже если я ее не пишу нигде. Какой ответ?Выделение строки с помощью malloc

Вот код:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main(int argc, char** argv) { 
    char *stringa1; 
    int n; 
    int i; 

    printf("How many characters in the string? "); 
    scanf("%d", &n); 

    stringa1 = (char*) malloc(n*sizeof(char)); 

    printf("Insert the string: "); 
    scanf("%s", stringa1); 

    free(stringa1); 

    return 0; 
} 
+1

Ваш код выглядит хорошо. 'scanf' помещает NUL (не NULL) в конец строки. Попробуйте вызвать 'strlen' прямо перед' free (stringa1) '. –

+1

Чтобы повторить то, что сказал @MichaelWalz, и чтобы nitpick, указатель может быть «NULL», а символ может быть «NUL». –

+0

В предыдущей версии я попробовал, и он возвращает число, которое я положил в первом 'scanf()'. – FranzGoogle

ответ

6

malloc() возвращает void* указатель на блок памяти, хранящийся в куче. Выделение с помощью malloc() не инициализирует какую-либо строку, а только место, которое нужно заняться.Чтобы добавить символ с нулевым завершающим символом, вам нужно либо сделать это самостоятельно, либо использовать такую ​​функцию, как scanf(), которая добавляет этот символ для вас. Сказав это, вам необходимо заранее выделить место для этого \0.

Ваш malloc() вызов должен быть вместо этого:

stringa1 = (char*) malloc((n+1)*sizeof(char)); /*+1 for '\0' character */ 

Примечание: Вам не нужно отбрасывать возвращение таНос. Для получения дополнительной информации см. this.

Другое дело отметить sizeof(char)1, поэтому умножение этого в вашем malloc() звонка не требуется.

Вам также необходимо проверить, возвращается ли malloc()NULL. Это можно сделать так:

if (stringa1 == NULL) { 
    /* handle exit */ 

Кроме того, вы можете использовать только strlen() на строку с завершающим нулем, в противном случае это заканчивается время undefined behaviour.

Вызывается scanf(), а stringa1 содержит несколько символов, вы можете позвонить ему strlen().

Кроме того, проверка возврата scanf() также является хорошей идеей. Вы можете проверить это следующим образом:

if (scanf("%d", &n) != 1) { 
    /* handle exit */ 

Ваш код с этими изменениями:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main(void) { 
    char *stringa1 = NULL; 
    size_t n, slen; 

    printf("How many characters in the string? "); 
    if (scanf("%zu", &n) != 1) { 
     printf("Invalid input\n"); 
     exit(EXIT_FAILURE); 
    } 

    stringa1 = malloc(n+1); 
    if (stringa1 == NULL) { 
     printf("Cannot allocate %zu bytes for string\n", n+1); 
     exit(EXIT_FAILURE); 
    } 

    printf("Insert the string: "); 
    scanf("%s", stringa1); 

    slen = strlen(stringa1); 
    printf("String: %s Length: %zu\n", stringa1, slen); 

    free(stringa1); 
    stringa1 = NULL; 

    return 0; 
} 
+0

Хорошо, это работает. Большое спасибо. Теперь у меня есть еще один вопрос: я не понимаю, как «if (scanf («% zu », & n)! = 1) {'works ... Извините за глупый вопрос: если я вставляю значение, отличное от '1', он должен возвращать« Invalid input »или нет? – FranzGoogle

+0

Он возвращает только недопустимый ввод, если число не было прочитано. уверен, что только номер '1' считывается в' n'. 'scanf()' просто проверьте сколько значений было прочитано. В этом случае вам нужно только одно значение для чтения, поэтому 'scanf()' проверяет это. если вы введете что-то вроде 'c', это будет означать ошибку, потому что номер не был прочитан. Если вы вводите что-то вроде '5', значит,' scanf' был успешным. – RoadRunner

+0

Хорошо, теперь это совершенно ясно! Большое спасибо! – FranzGoogle

8

если выделить строку, используя таНос (как в коде ниже), это символ NULL автоматически вставляется в конце строки?

Номер malloc() возвращает блок неинициализированной памяти.

Я знаю, что функции типа 'strlen' не работают, если нет символа NULL, и в этом коде я использую его, и он работает. Поэтому я думаю, что в конце моей строки есть «\ 0», даже если я ее нигде не написал.

scanf() вставляет нулевые байты ('\0') для вас, когда вы используете %s спецификатор формата (предполагая, что scanf() удалось).

От man scanf():

s Соответствует последовательности без пробельных символов; следующий указатель должен быть указателем на исходный элемент массива символов , который достаточно длинный, чтобы удерживать входную последовательность и завершающий нулевой байт ('\ 0'), который автоматически добавляется . Входная строка останавливается в белом пространстве или на максимальная ширина поля, в зависимости от того, что произойдет раньше.

(акцент мой).

Кстати, вы должны сделать проверку ошибок для звонков scanf() и malloc().

+1

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

+0

Спасибо, но я не могу понять, когда вы говорите об ошибке проверки 'scanf()' и 'malloc()' ... – FranzGoogle

+0

@FranzGoogle 'scanf()' возвращает количество проверенных файлов; в противном случае это провалилось. 'malloc()' возвращает NULL, если ему не удалось выделить память. Итак, я сказал, что вам нужно проверить код возврата этих функций, чтобы проверить, не сработали ли они. Например: 'if (scanf ("% d ", & n)! = 1) {/ * failure * /}' и 'stringa1 = (char *) malloc (n * sizeof (char)); if (stringa1 == NULL) {/ * failure * /} 'и т. д. –

1

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

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

Такие функции, как scanf и strcpy, добавить нулевой символ; такая функция, как strncpy, не всегда делает это.

+0

Итак, мой Код правильно? Я так понимаю ... – FranzGoogle

2

malloc возвращает указатель на неинициализированную степени памяти.

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

Примите во внимание, что, как правило, такой вопрос, как этот

printf("How many characters in the string? "); 

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

stringa1 = (char*)malloc((n + 1) *sizeof(char)); 

или

stringa1 = (char*)calloc(n + 1, sizeof(char)); 

В последнем случае вы можете применить функцию strlen, которая возвращает 0, поскольку степень памяти равна нулю инициализирован.

Этот вызов scanf

scanf("%s", stringa1); 

небезопасно. Вместо этого лучше использовать fgets. Например

fgets(stringa1, n + 1, stdin); 

Эта функция может добавить строку с новым символом строки.Чтобы удалить его со строки, вы можете написать

stringa1[strcspn(stringa1, "\n")] = '\0'; 
Смежные вопросы