#c #pointers
#c #указатели
Вопрос:
Привет и заранее спасибо,
Короче говоря, что я делаю, так это создаю указатель, который создает локальную переменную в стеке, а затем запрашиваю память с помощью malloc, который выделяет место в куче.
Затем я создаю локальный int в стеке.
Затем я запрашиваю у пользователей ввод через scanf.
Но при вводе последней цифры консоль исчезает и не выводит мне результат, даже если я пытаюсь сохранить его через getchar ()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE 80
int main()
{
char *student = malloc(MAX_LINE * sizeof(char));
int grade;
printf("Enter students name ");
scanf("%s", student);
printf("Enter students grade ");
scanf("%d", grade);// i would say it has to be grade and not amp;grade
// it vanishes right after here. Cant get to see any result
printf("%s received a %dn", student, grade);
free(student);
getchar();
}
Комментарии:
1. Даже если вы пишете amp; grade, происходит сбой.
Ответ №1:
scanf("%d", grade);
должно быть scanf("%d", amp;grade);
Вы должны передать адрес переменной / буфера, в котором вы хотите сохранить элемент ввода. И grade
ссылается на содержимое, там amp;
оператор addressof, работающий с grade
amp;grade
, выдает нам адрес переменной.
В случае scanf("%s", student);
the student
сам ссылается на адрес, то есть на содержимое переменной pointer, student
которая содержит базовый адрес блока памяти, который вы только что выделили. Следовательно, это правильно.
Аргументы всегда должны указывать на адрес расположения переменной / буфера, куда вы хотите scanf
поместить этот конкретный раздел этого ввода.
Допустим, изначально у вас есть мусор, 0x5964
хранящийся в grade
, и адрес памяти grade
является 0x1234abcd
. В scanf ("%d", grade);
, scanf
попытался бы записать прочитанное целое число в ячейку памяти 0x5964
, что недопустимо.
В то время как в scanf ("%d", amp;grade);
, scanf
сохранял бы прочитанное целым числом в ячейку памяти 0x1234abcd
. После этого обращение к grade
как к r-значению приведет к получению содержимого ячейки памяти 0x1234abcd
, это то, что вы хотите.
----------
| 0x5964 | <-------(uses this as address)--- -------------------
---------- <------ | |
| grade | (writes) scanf ("%d", grade); |
---------- (here) scanf ("%d", amp;grade); |
|0x1234abcd| | | |
---------- <------ (uses this as address)--- |
|
|
---------- |
| ?????? | <----------(tries to write here)----------------------
----------
| ??? |
----------
| 0x5964 |
----------
Комментарии:
1. Большое вам спасибо! Я собираюсь внедрить это в свою голову, даже если мне придется прочитать это 10 раз. Я читаю довольно много руководств, но каждое из них было неполным, поэтому из всех них я пытался составить целостную картину. Эти объяснения здесь, в этой теме, чрезвычайно хороши. Спасибо!
2. Что меня смутило, так это использование scanf, потому что с локальными переменными у меня не было проблем. Я часто делал что-то вроде, int * ptr; а затем int x = 5; а затем ptr = amp;x; в результате чего я мог сказать, что * ptr = 5; но scanf действовал по-другому.
3. вам не нужно заботиться о том, из стека это или из кучи, вы хотите убедиться, что адрес, на который вы передаете
scanf
, является действительным выделенным адресом. вint *ptr;
иint x;
иptr = amp;x
теперь, поскольку мы сохранили адресx
как значениеptr
, поэтому мы передаемamp;x
или мы передаемptr
одно и то же, поскольку они оба представляют одно и то же значение адреса, которое относится к локальной переменной и, следовательно, допустимо.
Ответ №2:
Вам следует использовать scanf("%d", amp;grade);
. scanf()
необходимо знать, куда записывать данные, поэтому ему нужен адрес переменной.
Ответ №3:
Ваш комментарий неверен, так и должно быть, amp;grade
потому что вам нужно передать адрес grade
, чтобы scanf
можно было изменять его через адрес памяти. Если вы передаете просто grade
, вы передаете scanf
значение grade
, которое является случайным мусором (или, возможно, 0 в зависимости от вашего компилятора), потому что вы его не инициализировали. scanf
затем думает, что случайное число (или 0 …) является адресом, и пытается изменить память по этому адресу, что приводит к сбою.
Чтобы getchar
приостановить программу, вызовите fflush(stdin)
после второго вызова scanf
.
Комментарии:
1. Спасибо. Я понимаю и согласен, но, даже если я это исправлю. Происходит тот же сбой. Я не знаю, почему
2. @запаздывающий вызов
fflush(stdin)
после того, как вы вызываетеscanf
второй раз.scanf
считывает входные данные, но не «удаляет» их из буфера, поэтому при вызовеgetchar
он видит символ и возвращает. Пожалуйста, отметьте это как ответ, если он ответил на ваш вопрос.3. Спасибо! блестяще! это работает! теперь это останавливается и позволяет мне видеть печать
Ответ №4:
Происходит сбой или просто не выводится результат?
Как происходит сбой?
В любом случае (после добавления оператора address-of в grade
) вы всегда должны проверять возвращаемое значение scanf
. В этом случае он должен возвращать 1, если все в порядке, 0 (или EOF) в противном случае.
int chk = scanf("%d", amp;grade);
if (chk == 1) {
/* rest of your program */
} else {
fprintf(stderr, "something went wrong in the scanf.n");
fprintf(stderr, "Return value was %dn", chk);
}
Я подозреваю, что вы вводите имя со встроенными пробелами (например, "full name"
). Выполнение этого присвоит "full"
значение student
и оставит " name"
в буфере готовым для следующей операции ввода. Попытка получить целое число оттуда завершится неудачей, и scanf возвращает 0, чтобы указать на этот сбой.