Я только что вошел в мир программирования на C и сейчас учусь использовать malloc
и free
.
Я написал короткий код упражнения для printf
строки, введенной с помощью scanf
, и у меня возникли проблемы с его компиляцией.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(void)
{
char *keyword;
printf("keyword: ");
scanf("%s", keyword);
if (keyword == NULL)
return 1;
char *t = malloc(strlen(keyword) + 1);
if (t == NULL)
return 1;
for (int i = 0, n = strlen(keyword) + 1; i < n; i++)
t[i] = keyword[i];
printf("t: %s\n", t);
free(t);
return 0;
}
Для отладки я написал тот же код, но без цикла for
(код ниже), и тогда код работал хорошо. Это привело меня к выводу, что проблема может быть в цикле for
, который используется для назначения символов соответствующим ячейкам памяти, но я до сих пор не могу найти решение.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(void)
{
char *keyword;
printf("keyword: ");
scanf("%s", keyword);
if (keyword == NULL)
return 1;
char *t = malloc(strlen(keyword) + 1);
if (t == NULL)
return 1;
t[0] = keyword[0];
t[1] = keyword[1];
t[2] = keyword[2];
t[3] = keyword[3];
t[4] = keyword[4];
t[5] = keyword[5];
printf("t: ");
printf("%c", t[0]);
printf("%c", t[1]);
printf("%c", t[2]);
printf("%c", t[3]);
printf("%c", t[4]);
printf("%c", t[5]);
printf("\n");
free(t);
return 0;
}
Я почти уверен, что это простая ошибка, но я не могу выяснить причину этой ошибки с помощью отладчика или онлайн. Я был бы очень признателен, если бы кто-нибудь помог мне решить эту проблему.
Что касается проблем со сборкой кода, то если вы новичок и не выполняете сборку с включенным дополнительным предупреждением, он действительно будет собран, но у вас, скорее всего, возникнут проблемы при его запуске. Вам нужно всегда включать дополнительные предупреждения (и действительно относиться к ним как к ошибкам), потому что компилятор сообщит вам о вашей проблеме.
@Someprogrammerdude Судя по тому, что я изучил и понял, *keyword
просто объявляет указатель, но не выделяет никакой памяти. И я подумал, что scanf
автоматически вычислит размер строки и соответствующим образом выделит память (честно говоря, я усвоил всего несколько процентов всех этих концепций, таких как указатель, выделение памяти или scanf
, и признаю, что мне нужно больше учиться, чтобы понять их).
@Someprogrammerdude Также я ценю твой совет. Мой отладчик не обнаружил никаких проблем при запуске второго кода, и я решил, что его можно использовать char *keyword;
. Включение дополнительных предупреждений мне очень поможет в дальнейшем!
«Я думал, что scanf
автоматически вычислит размер строки и соответствующим образом выделит память». К сожалению, это невозможно. Ни одна функция в C, созданная пользователем или одна из стандартных функций, не может изменить свой аргумент для вызывающей стороны. Это, конечно, означает, что указатель, переданный scanf
, не может быть изменен функцией. Он изменяет память, на которую указывает указатель. Кроме того, если вы не инициализируете локальную переменную, ее значение будет неопределенным (смотрите на это как на мусор), что в вашем случае означает, что keyword
может указывать куда угодно.
@Woodrow scanf
не выделяет память. Он ожидает передачи действительных адресов буферов/переменных.
Вы не выделили память для ключевого слова, что иногда может не вызвать ошибку, но инициализировать указатель необходимо. Неинициализированный указатель может указывать на любое место в памяти, что приводит к неопределенному поведению и потенциально изменяет важную память.
and then the code worked well.
...
ЭТО НЕ РАБОТА well
!!
Это просто потому что... ты счастливчик....
Прежде всего, когда вы компилируете свой код, вы можете получить предупреждающее сообщение об этом коде:
char *keyword;
scanf("%s", keyword);
Потому что,
keyword
.keyword
неопределенен, вы используете его в качестве входного указателя для scanf()
.Итак, где хранить данные с входа «scanf()»?? Это определенно место памяти!
Итак, вам повезло, что ваша программа не вышла из строя...
НЕ игнорируйте предупреждающее сообщение в любой ситуации!
В вашем случае лучше изменить его на:
char keyword[1048575];
scanf("%s", &keyword);
-или-
char *keyword = malloc(1048575);
scanf("%s", keyword);
Тогда вы можете плавно столкнуться с провалом.
~наслаждайся~
Хотя не следует жадничать с размерами массива, 1048575
— это слишком много. Более пары сотен элементов — это просто пустая трата места.
@Someprogrammerdude Да, но он должен выяснить эту проблему и исправить ее самостоятельно。
Следующие строки:
char *keyword;
printf("keyword: ");
scanf("%s", keyword);
if (keyword == NULL)
return 1;
Есть несколько проблем:
keyword
не инициализируется. Его необходимо инициализировать, чтобы он указывал на некоторый буфер/память, чтобы scanf
войти в него в scanf("%s", keyword);
.
Неинициализированный доступ к нему вызывает неопределенное поведение (UB).
Чтобы его инициализировать, вам следует определить максимальную длину, которую вы для него допускаете, а затем инициализировать его следующим образом:
(1) Использование malloc
(2) Использование распределения стека (если максимальный размер относительно невелик)
(3) Установка его так, чтобы он указывал на какой-то существующий буфер
Не забудьте добавить 1 к максимальной длине при выделении для нулевого завершения.
После определения максимальной длины keyword
вы должны передать это значение scanf
, чтобы убедиться, что буфер не переполнен, например:
... = scanf("%33s", keyword); // here the maximum length is 33
Вы всегда должны проверять возвращаемое значение scanf. Если это удалось, он возвращает:
Количество успешно назначенных аргументов приема
(здесь должно быть 1).
(keyword == NULL)
вряд ли будет правдой (разве что случайно), независимо от того, удалось scanf
или нет. И если вы правильно его инициализируете, как описано выше, этого никогда не будет NULL
.
Когда вы это делаете
scanf("%s", keyword)
, на что указываетkeyword
? Что ваши материалы для начинающих (курсы, учебные пособия, учителя, книги и т. д.) говорят оscanf
, его спецификаторах формата и соответствующих аргументах?