Как написать в указатель напрямую, используя функцию gets()?

Я получил этот тестовый код и просто любопытно, почему передача указателя на gets() приводит к ошибке во время выполнения?

void main()
{
    char *value="gogo";
    puts(value);
    value="11";
    puts(value);
    gets(value);
}

3 ответа

Так как char *value="gogo"; скорее всего, чем не выделены для чтения только память!

Лучше:

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

#define MAX_LINE 80

int main()
{
    char value[MAX_LINE] ="gogo";
    puts(value);
    strcpy (value, "11");
    puts(value);
    fgets(value, MAX_LINE, stdin);
    puts(value);
    return 0;
}

Вот хорошая ссылка с более подробной информацией: Хранилище для строк в C

PS:

получает () это зло. Избегайте этого, если это вообще возможно: почему gets() - это плохо

Указатель value указывает на (статический массив, связанный с) строковый литерал.

Попытка изменить строковый литерал имеет неопределенное поведение. В этом случае ваш компилятор хранит строку "gogo" в памяти, помеченной операционной системой как доступная только для чтения, и попытка ее изменения вызывает сбой вашей программы.

Если вы объявляете указатель на строковый литерал, вы должны определить его как const:

const char *value = "gogo";

поэтому компилятор будет диагностировать любую попытку изменить его. Или, если вы действительно хотите изменить строку, определите ее как массив:

char value[] = "gogo";

что означает, что вы не можете присвоить значение value, но вы можете использовать strcpy обновить его.

Еще несколько проблем:

void main() неправильно [*]; правильное определение int main(void), Если вы используете книгу, которая сказала вам использовать void main()пожалуйста, найдите лучше; его автор не очень хорошо знает С.

Никогда не используйте gets функция; это по своей сути небезопасно и было удалено из языка. (Он не может защитить от ввода длиннее, чем массив, в котором хранится значение.) Вы можете использовать fgets вместо; это немного сложнее в использовании, но его можно использовать безопасно.

Вам нужно добавить

#include <stdio.h>

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

[*] Говоря это void main() неправильно немного завышает дело. Соответствующий компилятор может разрешить это, и компилятор не должен жаловаться на это, но нет веских оснований для того, чтобы воспользоваться этим. int main(void) всегда правильно. Любая книга или учебник по Си, которые пропагандируют использование void main() был почти наверняка написан кем-то, кто не знает C достаточно хорошо, чтобы писать книги или учебные пособия по этому поводу.

Здесь ваш указатель указывает на строковый литерал ("gogo"). Строковые литералы не гарантируются для записи. Вы должны выделить свою собственную память:

char value[50] = "gogo";
...
gets(value);

Тем не менее, это не безопасно, так как gets не принимает размер буфера, и, следовательно, может переполнить ваш буфер. (Что также может привести к ошибке во время выполнения). НИКОГДА не используйте gets, как говорится на странице руководства:

ОШИБКИ

Никогда не используйте gets(), Потому что невозможно предсказать, не зная данных заранее, сколько символов gets() будет читать, а потому gets() будет продолжать хранить символы после конца буфера, это чрезвычайно опасно для использования. Он был использован для взлома компьютерной безопасности. использование fgets() вместо.

Намного лучше выделить свою память

char user_input[200];
fgets(user_input, 200, stdin);

Вам может понадобиться проверить user_input, чтобы увидеть, заканчивается ли это новой строкой. Если это так, то fgets прочитайте целую строку. Если этого не произойдет, то пользователь наберет более ~200 символов в строке, и вам нужно будет прочитать больше, чтобы получить всю строку. Я использовал 200 Вот. Выберите размер, который имеет смысл для ваших данных. Вы также можете использовать malloc выделять память "на лету" и помещать fgets в цикл, чтобы прочитать всю строку в буфер.

Другие вопросы по тегам