Как правильно использовать scanf с массивами в al oop in C? - PullRequest
3 голосов
/ 01 мая 2020

Я новичок в C программировании, и я не знаю, что я делаю неправильно. У меня есть метод main, и я создал структуру.

Мне нужно создать массив в основной части этой структуры, а затем присвоить значения через scanf в for для l oop.

Моя программа компилируется без ошибок, но после ввода чего-либо в консоль выдает исключения, которые я не понимаю. Исключения, которые я получаю:

Warning C4477   'scanf_s' : format string '%s' requires an argument of type 'char *', but variadic argument 1 has type 'char **'

Warning C4473   'scanf_s' : not enough arguments passed for format string   

Вот как выглядит мой код:

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>

struct Employee {
    char *ccFirstName;
    char *ccLastName;
    int iAge;
};

int main(void) {
    struct Employee sExampleEmployee[3];

    for (int i = 0; i < 3; i++) {
        printf("Geben Sie den Namen :");
        sExampleEmployee[i].ccFirstName = scanf_s("%s", &sExampleEmployee->ccFirstName);
        sExampleEmployee[i].ccLastName = scanf_s("%s", &sExampleEmployee->ccLastName);
        sExampleEmployee[i].iAge = scanf_s("%d", &sExampleEmployee->iAge);
    }

    for (int i = 0; i < 3; i++) {
        printf("First name of the employee: %s", sExampleEmployee[i].ccFirstName);
        printf("Last name of the employee : %s", sExampleEmployee[i].ccLastName);
        printf("Age of the employee: %d", sExampleEmployee[i].iAge);
    }
    return EXIT_SUCCESS;
}

Ответы [ 2 ]

2 голосов
/ 01 мая 2020

Кажется, у вас есть несколько «точек замешательства»!

Во-первых, возвращаемое значение функции scanf_s равно не фактическому прочитанному значению, а скорее число элементов успешно отсканировано. Таким образом, ваши назначения, такие как sExampleEmployee[i].ccFirstName = scanf_s(..., не будут делать ничего похожего на то, что, по вашему мнению, будет.

Во-вторых, ваше использование sExampleEmployee-> не получит поле структуры какой-либо структуры, но первое - как имя массива, используемое без индекса [], фактически будет указателем на первый член массива. (См. Следующий пункт о массивах!)

В-третьих (и очень важно), вы не назначили никакой памяти элементам структуры ccFirstName и ccLastName - они просто неинициализированные указатели , Вам лучше объявить их как массивы фиксированной длины: достаточно долго, чтобы вместить любой возможный ввод плюс требуемый завершающий nul символ.

Наконец (более тонкая проблема), когда у вас есть строковый аргумент (соответствующий спецификатору формата %s) в функции scanf_s, вам нужно добавить дополнительный аргумент (сразу после строки), указывающий размер этого строкового буфера (чтобы предотвратить чтение слишком большого количества символов ).

Итак, имея в виду эти моменты, вы должны переопределить свою структуру и переписать свой ввод l oop, чтобы что-то вроде этого:

#define MAXNAMELEN 100 // Use whatever value you want - this will allow 99 letters
struct Employee
{
   char ccFirstName[MAXNAMELEN];
   char ccLastName[MAXNAMELEN];
   int iAge;
};
//...
   for (int i = 0; i < 3; i++)
   {
      printf("Geben Sie den Namen :");
      scanf_s("%s", sExampleEmployee[i].ccFirstName, MAXNAMELEN); // Arrays (strings) are automatically...
      scanf_s("%s", sExampleEmployee[i].ccLastName, MAXNAMELEN);  // ... pointers!
      scanf_s("%d", &(ExampleEmployee[i].iAge)); // But integers need the "&"
   }

EDIT: Для получения дополнительной информации о функции scanf_s, см. Здесь . Важная часть (для вашего случая) такова:

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

NOTE : как видно из документации MS, аргумент size после указателя для %s имеет тип unsigned для реализации Microsoft scanf_s, тогда как он должен иметь тип rsize_t в соответствии с C Стандартным приложением K. Тип rsize_t указан там, как и size_t, который может иметь размер, отличный от unsigned int, и действительно, он работает на 64-битных архитектурах для Linux и Windows, поэтому MS do c указывает, что параметр размера имеет тип unsigned, а не size_t. Используйте преобразование stati c для преобразования значения size_t в unsigned для 64-разрядных конфигураций сборки , очень своеобразный подход к переносимости.

По этой и другим причинам scanf_s не должен использоваться в переносимом коде.

0 голосов
/ 01 мая 2020

Я думаю, что вы хотите хранить информацию для 3 сотрудников при использовании массива sExampleEmployee[3];.

Вы должны найти память для ccFirstName et ccLastName в каждом элементе структуры.

for (int i = 0; i < 3; i++) {
   sExampleEmployee[i].ccFirstName = malloc(sizeof(char)*30); // max length of name is up to 29.
   if(!sExampleEmployee[i].ccFirstName) {
      // handle the error;
   }
   sExampleEmployee[i].ccLastName = malloc(sizeof(char)*30);
   if(!sExampleEmployee[i].ccLastName) {
      // handle the error;
   }
}
sExampleEmployee[i].ccFirstName = scanf_s("%s", &sExampleEmployee->ccFirstName);
sExampleEmployee[i].ccLastName = scanf_s("%s", &sExampleEmployee->ccLastName);
sExampleEmployee[i].iAge = scanf_s("%d", &sExampleEmployee->iAge);

должно стать (удалите амперсанд &, если хотите введите строку):

scanf_s("%s", sExampleEmployee[i].ccFirstName);
scanf_s("%s", sExampleEmployee[i].ccLastName);
scanf_s("%d", &sExampleEmployee[i].iAge);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...