C, указатели, консоль исчезает при вводе данных

#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, чтобы указать на этот сбой.