(edit: other posters have reminded me of the offsetof macro that makes this much more humane)
C doesn't automatically know how to do this. You want your program to know, at run-time, what the attributes of Person are called ("cpf", "name", etc.). However, when you're programming in C, your program doesn't know that. The compiler knows what things are called, but it doesn't store that information in your compiled program. In dynamic languages like Python, there's less separation between the compiler and your program, and you can do things like this. But in C, what you write is what you get.
However, this is still achievable with a little extra work. You just need to explicitly tell your program what it needs to know. Your program needs to know what the name of each attribute is, how to read it, and where it's stored in the struct. Since the compiler doesn't store this information in your program automatically, you need to store it explicitly in your code, like this:
#include "stdio.h"
#include "stddef.h"
#include "stdint.h"
typedef struct
{
char cpf[80];
char name[80];
char Sex[80];
int32_t dtBorn;
char city[80];
char UF[80];
} Person;
typedef struct
{
char *label; // What the attribute is called
char *scanf_pattern; // How to read it with scanf
ptrdiff_t offset; // Where in the struct the attribute is located
} AttributeInfo;
static const AttributeInfo attributes[] = {
{"cpf", " %79[^\n]s", offsetof(Person, cpf)},
{"name", " %79[^\n]s", offsetof(Person, name)},
{"Sex", " %79[^\n]s", offsetof(Person, Sex)},
{"dtBorn", "%d", offsetof(Person, dtBorn)},
{"city", " %79[^\n]s", offsetof(Person, city)},
{"UF", " %79[^\n]s", offsetof(Person, UF)}
};
Now the attributes
constant has all the extra information you need. For each attribute, it remembers the name of the attribute, the scanf
format string for the attribute, and the offset in bytes from the start of the Person
struct to where that attribute is (that's what the offsetof
macro computes for us; https://en.wikipedia.org/wiki/Offsetof has more info on that).
Now, we've saved the extra information we need in attributes
. Even at run-time, our program has the stored information needed to do what you want to do. We just need to explicitly use it like so:
int main(int argc, char **argv) {
Person pw;
for (size_t i = 0; i < sizeof(attributes) / sizeof(AttributeInfo); i++)
{
AttributeInfo attribute = attributes[i];
printf("Input person's %s: \n", attribute.label);
int success = scanf(attribute.scanf_pattern, (void*) &pw + attribute.offset);
if (success != 1) {
printf("Not valid; try again.\n");
scanf("%*[^\n]s");
--i;
}
}
printf("cpf: %s\n", pw.cpf);
printf("name: %s\n", pw.name);
printf("Sex: %s\n", pw.Sex);
printf("dtBorn: %d\n", pw.dtBorn);
printf("city: %s\n", pw.city);
printf("UF: %s\n", pw.UF);
}
When we compile and run the program, we will get:
$ gcc foo.c -o foo
...
$ ./foo
Input person's cpf:
clam protection factor
Input person's name:
Super Foonly
Input person's Sex:
undecided
Input person's dtBorn:
yesterday
Not valid; try again.
Input person's dtBorn:
19700101
Input person's city:
Anytown
Input person's UF:
ulterior freshness
cpf: clam protection factor
name: Super Foonly
Sex: undecided
dtBorn: 19700101
city: Anytown
UF: ulterior freshness
Your question was clear about what you were asking. However, here are some issues you should be aware of that your original version had:
cpf
, name
, etc. were only single characters, not strings (arrays of characters). I don't know what "cpf" and "UF" are, but I assume you want name, city and Sex to be strings.
- Your scanf format didn't have a width specifier (the
79
in " %79[^\n]s"
above). This lets someone crash or exploit your program by typing in a longer string than you expected. Have a look at http://www.crasseux.com/books/ctutorial/String-overflows-with-scanf.html for more discussion of this issue.
And I understand that these may have been for example purposes and intentional on your part, but just in case they weren't:
- You didn't have a main() method. You can't just put a for-loop in your .c file at top level; it needs to be inside a function.
- It's best not to hardcode loop lengths (the
6
in your for-loop). See https://en.wikipedia.org/wiki/Magic_number_(programming) for more info on this rule of programming.
Looks like you're making the mistakes that everyone makes when they're learning C for the first time. But what you wanted to do is doable and reasonable, and I hope this helps communicate how it could be done. You might want to come back to this after you've spent a little more time thinking about pointer math, depending on your comfort level. But no worries! You'll have it in no time.