I am wondering why would some one use nested structures in C lang?
I read many articles and books on structs but they don't seem to help me, all they said was it's just easy to pass structures to functions as arguments, but aren't they the same thing as writing all the data types in one structure and just simply pass that structure or just use the (.
) member operator to pass the data to the function?
Below is a sample code where a nested structure is used.
#include <stdio.h>
struct address {
char city[20];
int pin;
char phone[14];
};
struct employee {
char name[20];
struct address add;
};
void main() {
struct employee emp;
printf("Enter employee information?\n");
scanf("%s %s %d %s", emp.name, emp.add.city, &emp.add.pin, emp.add.phone);
printf("Printing the employee information....\n");
printf("name: %s\nCity: %s\nPincode: %d\nPhone: %s",
emp.name, emp.add.city, emp.add.pin, emp.add.phone);
}
Here, in the above code rather than using a separate structure for address, isn't it easy to do something like this:
struct employee {
char name[20];
char city[20];
int pin;
char phone[14];
} emp;
if we would have done like this then when we had to access the members we would have saved a few characters?
like instead of using emp.add.pin
now we would simply use emp.pin
.
I think its just for neat organization of variables like if we would use emp.pin
then we might get confused if its employee's pin for some thing? rather than when we use emp.add.pin
then this makes it clear that the pin that we are talking about is of the employee's address pin, not something else?
Is that all the use of nested structures, ORGANIZATION of stuff?
What are your thoughts on this?
CodePudding user response:
Grouping information in meaningful structures is useful to write functions that deal with the group independently of whether it is a stand alone structure or part of a bigger one.
For example, if you have an address input or printing function, you can call it for emp.add
if you use a struct for the employee address, but you cannot if you merge the fields into the employee structure.
It is also very useful to use structure fields to ensure consistent definition across all uses.
For example:
#include <stdio.h>
struct address {
char city[30];
char zipcode[10];
char street1[40];
char street2[40];
char phone[14];
};
struct employee {
char name[32];
char pin[5];
struct address add;
};
struct company {
char name[32];
char taxid[12];
struct address add;
};
int get_string(const char *prompt, char *dest, size_t size) {
int c;
size_t i = 0;
printf("Enter %s: ", prompt);
while ((c = getchar()) != EOF && c != '\n') {
if (i 1 < size)
dest[i ] = c;
}
dest[i] = '\0';
return (i == 0 && c == EOF) ? -1 : i;
}
void get_address(struct address *ap) {
get_string("city", ap->city, sizeof ap->city);
get_string("zipcode", ap->zipcode, sizeof ap->zipcode);
get_string("street1", ap->street1, sizeof ap->street1);
get_string("street2", ap->street2, sizeof ap->street2);
get_string("phone", ap->phone, sizeof ap->phone);
}
void print_address(struct address *ap) {
printf("city: %s\n", ap->city);
printf("zipcode: %s\n", ap->zipcode);
printf("street1: %s\n", ap->street1);
printf("street2: %s\n", ap->street2);
printf("phone: %s\n", ap->phone);
}
int main() {
struct employee emp;
struct company comp;
printf("Enter employee information:\n");
get_string("employee name", emp.name, sizeof emp.name);
get_string("employee pin", emp.pin, sizeof emp.pin);
get_address(&emp.add);
printf("Printing the employee information....\n");
printf("name: %s\npincode: %s\n", emp.name, emp.pin);
print_address(&emp.add);
printf("Enter company information:\n");
get_string("company name", comp.name, sizeof comp.name);
get_string("company taxid", comp.taxid, sizeof comp.taxid);
get_address(&comp.add);
printf("Printing the company information....\n");
printf("name: %s\ntaxid: %s\n", comp.name, comp.taxid);
print_address(&comp.add);
return 0;
}
CodePudding user response:
Demonstrating the virtues of nested structs vs no nested structs
Grouping variables within a structure within a structure is like grouping lines within a spreadsheet within a file. You might say: "why do I need multiple files? Why can't I just put all 100 of my spreadsheets in the same file?" Or, why can't I put all lines within 1 spreadsheet within 1 file? Well, you technically can put all 100 of your spreadsheets within 1 file, or you can put all lines within 1 spreadsheet with in 1 file, or you can put all characters within 1 line within 1 spreadsheet within 1 file, but using logical groups makes the content the most organized, findable, and readable.
The same goes with folders on your computer. Your question is even more like saying: "I don't see the point of having folders within folders. Why can't I just have no folders at all, or just one layer of folders, but no folders within folders?" Again, technically you can remove all user folders and just have all files within 1 folder, or just have one layer of user folders and never have more folders within those folders, but that would dramatically reduce your ability to organize your files!
The same goes with structures, and structures within structures. They are useful for organization, just like different spreadsheets within files, or folders within folders.
Furthermore, using a structure within a structure can reduce redundancy and make the code shorter and much easier to write, to use, and to reuse.
Consider the following examples, both of which are now in my eRCaGuy_hello_world repo:
1. WithOUT nested structs (it's ok; it works; but, it's very redundant)
struct_basic_demo_withOUT_nested_structs.c:
#include <stdbool.h> // For `true` (`1`) and `false` (`0`) macros in C
#include <stdint.h> // For `uint8_t`, `int8_t`, etc.
#include <stdio.h> // For `printf()`
#include <string.h> // `strncpy()`
/// A function-like macro to write string `string` into destination char array
/// `destination`.
#define SET_STRING(destination, string) \
strncpy((destination), (string), sizeof(destination))
typedef struct addresses_s
{
char home_street[40];
char home_city[30];
char home_zipcode[10];
char home_state[30];
char home_country[30];
char work_street[40];
char work_city[30];
char work_zipcode[10];
char work_state[30];
char work_country[30];
char other_street[40];
char other_city[30];
char other_zipcode[10];
char other_state[30];
char other_country[30];
} addresses_t;
void print_addresses(addresses_t addresses)
{
printf(
"home_street: %s\n"
"home_city: %s\n"
"home_zipcode: %s\n"
"home_state: %s\n"
"home_country: %s\n"
"\n"
"work_street: %s\n"
"work_city: %s\n"
"work_zipcode: %s\n"
"work_state: %s\n"
"work_country: %s\n"
"\n"
"other_street: %s\n"
"other_city: %s\n"
"other_zipcode: %s\n"
"other_state: %s\n"
"other_country: %s\n"
"\n",
addresses.home_street,
addresses.home_city,
addresses.home_zipcode,
addresses.home_state,
addresses.home_country,
addresses.work_street,
addresses.work_city,
addresses.work_zipcode,
addresses.work_state,
addresses.work_country,
addresses.other_street,
addresses.other_city,
addresses.other_zipcode,
addresses.other_state,
addresses.other_country);
}
// int main(int argc, char *argv[]) // alternative prototype
int main()
{
printf("struct basic demo withOUT nested structs.\n\n");
addresses_t addresses;
SET_STRING(addresses.home_street, "street 1");
SET_STRING(addresses.home_city, "city 1");
SET_STRING(addresses.home_zipcode, "12345");
SET_STRING(addresses.home_state, "Florida");
SET_STRING(addresses.home_country, "USA");
SET_STRING(addresses.work_street, "street 2");
SET_STRING(addresses.work_city, "city 2");
SET_STRING(addresses.work_zipcode, "67890");
SET_STRING(addresses.work_state, "Florida");
SET_STRING(addresses.work_country, "USA");
SET_STRING(addresses.other_street, "street 3");
SET_STRING(addresses.other_city, "city 3");
SET_STRING(addresses.other_zipcode, "54321");
SET_STRING(addresses.other_state, "Florida");
SET_STRING(addresses.other_country, "USA");
print_addresses(addresses);
return 0;
}
Sample compile & run command and output:
eRCaGuy_hello_world/c$ gcc -Wall -Wextra -Werror -O3 -std=gnu17 struct_basic_demo_withOUT_nested_structs.c -o bin/a -lm && bin/a
struct basic demo withOUT nested structs.
home_street: street 1
home_city: city 1
home_zipcode: 12345
home_state: Florida
home_country: USA
work_street: street 2
work_city: city 2
work_zipcode: 67890
work_state: Florida
work_country: USA
other_street: street 3
other_city: city 3
other_zipcode: 54321
other_state: Florida
other_country: USA
2. WITH nested structs (much better, more modular, shorter, and easier to organize and use!)
struct_basic_demo_WITH_nested_structs.c:
#include <stdbool.h> // For `true` (`1`) and `false` (`0`) macros in C
#include <stdint.h> // For `uint8_t`, `int8_t`, etc.
#include <stdio.h> // For `printf()`
#include <string.h> // `strncpy()`
/// A function-like macro to write string `string` into destination char array
/// `destination`.
#define SET_STRING(destination, string) \
strncpy((destination), (string), sizeof(destination))
typedef struct address_s
{
char street[40];
char city[30];
char zipcode[10];
char state[30];
char country[30];
} address_t;
typedef struct addresses_s
{
address_t home;
address_t work;
address_t other;
} addresses_t;
void print_address(address_t address, const char* prefix)
{
printf(
"%s.street: %s\n"
"%s.city: %s\n"
"%s.zipcode: %s\n"
"%s.state: %s\n"
"%s.country: %s\n"
"\n",
prefix, address.street,
prefix, address.city,
prefix, address.zipcode,
prefix, address.state,
prefix, address.country);
}
void print_addresses(addresses_t addresses)
{
print_address(addresses.home, "home");
print_address(addresses.work, "work");
print_address(addresses.other, "other");
}
// int main(int argc, char *argv[]) // alternative prototype
int main()
{
printf("struct basic demo WITH nested structs.\n\n");
addresses_t addresses;
SET_STRING(addresses.home.street, "street 1");
SET_STRING(addresses.home.city, "city 1");
SET_STRING(addresses.home.zipcode, "12345");
SET_STRING(addresses.home.state, "Florida");
SET_STRING(addresses.home.country, "USA");
SET_STRING(addresses.work.street, "street 2");
SET_STRING(addresses.work.city, "city 2");
SET_STRING(addresses.work.zipcode, "67890");
SET_STRING(addresses.work.state, "Florida");
SET_STRING(addresses.work.country, "USA");
SET_STRING(addresses.other.street, "street 3");
SET_STRING(addresses.other.city, "city 3");
SET_STRING(addresses.other.zipcode, "54321");
SET_STRING(addresses.other.state, "Florida");
SET_STRING(addresses.other.country, "USA");
print_addresses(addresses);
return 0;
}
Sample compile & run command and output:
eRCaGuy_hello_world/c$ gcc -Wall -Wextra -Werror -O3 -std=gnu17 struct_basic_demo_WITH_nested_structs.c -o bin/a -lm && bin/a
struct basic demo WITH nested structs.
home.street: street 1
home.city: city 1
home.zipcode: 12345
home.state: Florida
home.country: USA
work.street: street 2
work.city: city 2
work.zipcode: 67890
work.state: Florida
work.country: USA
other.street: street 3
other.city: city 3
other.zipcode: 54321
other.state: Florida
other.country: USA