Нарушение прав доступа в scanf_s - PullRequest
0 голосов
/ 29 октября 2018

Я пытаюсь создать программу, чтобы просто посмотреть, что я могу сделать со структурами в C. Но получаю ошибку в основной функции в scanf_s("%s", &user.name):

Исключение, генерируемое в 0x5C26D3EC (ucrtbased.dll) в StructureTest.exe:

0xC0000005: Место записи нарушения доступа 0x01341000. произошло

Я также получаю предупреждения компилятора . Это мой код:

#include <stdio.h>

struct birthdate {
    int day;
    char month[9];
    int year;
};

typedef struct birthdate dob;
    struct info {
    char name[40];
    dob birthdate;
    int age;
    char sex[6];
    char *origin; 
};
void printinfo(struct info user) {
    printf("---- User Data ----\n");
    printf("Name: %s\n", user.name);
    printf("Date of birth: %d/%s/%d\n", user.birthdate.day, 
    user.birthdate.month, user.birthdate.year);
    printf("Age: %d\n", user.age);
    printf("Sex: %s\n", user.sex);
    printf("Country of origin: %s", user.origin);
}

int main() {
    printf("--Please enter your info--\n");
    struct info user;   
    printf("Please enter your name: ");
    scanf_s("%s", &user.name); // <-- exception thrown here
    printf("Please enter your date of birth in the format (dd/mm/yyyy): ");
    scanf_s("%d %s %d", &user.birthdate.day, &user.birthdate.month,
    &user.birthdate.year);
    printf("Please enter your age: ");
    scanf_s("%d", &user.age);
    printf("Please enter your gender ([M]ale/[F]emale): ");
    scanf_s("%s", &user.sex);
    printf("Please enter your country of origin: ");
    scanf_s("%s", &user.origin); // <- Another exception thrown here

    printf("\n\n");
    printinfo(user);

    printf("\nPress ENTER to continue..");
    getchar();
    return 0;
}

У меня пока нет опыта работы со структурами, но я подозреваю, что это может иметь какое-то отношение к массивам и указателям, а имя, которое я пишу, уходит в никуда.

Ответы [ 2 ]

0 голосов
/ 31 октября 2018

Помимо проблем с использованием scanf_s, упомянутых в другом ответе , вы также указываете неверный параметр:

scanf_s("%s", &user.origin);

Если origin является указателем на char, это неверный тип. Вам необходимо предоставить char *, но вы предоставляете char **.

0 голосов
/ 30 октября 2018

Вы не показали ввод, который вы вводите в программу.

В вашей программе есть незначительные ошибки и некоторые существенные:

  • Во-первых, вы были слишком резкимив распределении char массивов.Например, поле month в структуре birthdate содержит только 9 пробелов для хранения месяца, и это означает, что вы не можете хранить месяц, например september, для которого требуется 9 символов плюс еще один для символа \0 nulв конце строки .Это может быть проблемой с вашим выполнением, если вы не будете осторожны.
  • Это не распространенная практика - передавать struct s напрямую по значению в функцию, так как это делаеткомпилятор для копирования всего содержимого структуры в стек параметров.Распространено передавать структуру по ссылке, как в

    void printinfo(struct info *user);
    

    , а затем вызывать ее как

    printinfo(&user);
    

    , что заставляет компилятор передавать только указатель на структуру, экономя времяи память.

Я не нашел функцию scanf_s в своем руководстве онлайн, где вы ее взяли?Ну, после некоторого копания я нашел их ... из руководства VC для этих функций (не стандартно, просто расширение Microsoft):

В отличие от scanf и wscanf, scanf_s и wscanf_s требуют размер буфера, который должен быть указан для всех входных параметров типа c, C, s, S или наборов управления строк, которые заключены в [].Размер буфера в символах передается как дополнительный параметр, следующий сразу за указателем на буфер или переменную ...

, поэтому необходимо использовать

scanf_s("%s", &user.name, sizeof user.name - 1);

и то же самое для других строк, которые вы читаете.

NOTE

Эти суффиксированные функции _s являются только расширениями Microsoft для их компилятора .Они не являются переносимыми (и в любом случае стандартными) и не появляются в большинстве реализаций Си.Лучше их не использовать, кроме случаев, когда вы собираетесь использовать только компиляторы Microsoft C (и вам не гарантируется, что они исчезнут в будущем).Есть и другие способы проверить размер буфера, кроме использования нестандартных функций, например

scanf("%.39s", user.name); /* there's no need to use the & operator here */

(если вам нужно передать размер в качестве параметра, вы можете сделать следующее):

SCANF("%.*s", sizeof user.name - 1, user.name);

выполнит работу, или

fgets(user.name, sizeof user.name, stdin);

(этот вызов требует, чтобы вы исключили последний \n из строки) оба эти вызова являются стандартными, включены в <stdio.h>.

...