简体   繁体   中英

How to use scanf properly with Arrays in a loop in C?

I am new to C programming, and I don't know what I'm doing wrong. I have a main method and I have made a struct.

I need to make an array in main of that struct and then assign the values via scanf in the for loop.

My program compiles without an error, but after entering anything in the console, it throws exceptions that I do not understand. The exceptions that I get are:

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   

Here is how my code looks like:

#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;
}

You have several 'points of confusion', it would seem!

First, the return value of the scanf_s function is not the actual value read, but rather the number of items successfully scanned. So, your assignments like sExampleEmployee[i].ccFirstName = scanf_s(... won't do anything like what you appear to think they will.

Second, your sExampleEmployee-> usage won't get the structure field of any structure but the first - as an array name used without an [] index will, effectively, be a pointer to the first member of the array. (See next point on arrays!)

Third (and very important), you have not assigned any memory to the ccFirstName and ccLastName structure members - they are just uninitialized pointers. You would be better off declaring them as arrays of fixed length: long enough to hold any possible input plus the required terminating nul character.

Finally (a more subtle problem), when you have a string argument (corresponding to the %s format specifier) in the scanf_s function, you need to add an extra argument (immediately after the string) specifying the size of that string buffer (to prevent reading in too many characters).

So, with these points in mind, you should re-define your structure, and re-write your input loop, to something along these lines:

#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: For more information on the scanf_s function, see here . The important part (for your case) is this:

Unlike scanf and wscanf , scanf_s and wscanf_s require you to specify buffer sizes for some parameters. Specify the sizes for all c , C , s , S , or string control set [] parameters. The buffer size in characters is passed as an additional parameter. It immediately follows the pointer to the buffer or variable.

NOTE : as can be seen in the MS documentation, the size argument after the pointer for %s has type unsigned for Microsoft's implementation of scanf_s , whereas it must have type rsize_t as per the C Standard Annex K. Type rsize_t is specified there as being the same as size_t which may have a different size from unsigned int , and indeed it does on 64-bit architectures for both Linux and Windows, so the MS doc specifies that The size parameter is of type unsigned , not size_t . Use a static cast to convert a size_t value to unsigned for 64-bit build configurations , A very peculiar approach to portability.

For this and other reasons, scanf_s should not be used in portable code.

I think you want to store info for 3 employees when you use the array sExampleEmployee[3]; .

You have to locate the memory for ccFirstName et ccLastName in each struct element.

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);

should become (remove the ampersand & when you want to input the string):

scanf_s("%s", sExampleEmployee[i].ccFirstName);
scanf_s("%s", sExampleEmployee[i].ccLastName);
scanf_s("%d", &sExampleEmployee[i].iAge);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM