Mastering C Structures: From Declaration to Bit Fields
This article provides a comprehensive guide to C structures, covering declaration, variable definition, typedef aliases, initialization methods, pointer usage, member access, memory layout, nested structs, and bit fields, complete with code examples and visual illustrations to help readers understand and apply these concepts effectively.
Structs
Struct (Structure) is a data type composed of members of different types. By defining a struct we can combine multiple data types into a single type.
To use a struct, first declare the type, then define variables of that type.
Declaring a struct type
Use the struct keyword:
struct tag {
member
member
...
} variable-list;tag : struct type name.
member : struct members, defined like normal variables, e.g., int i.
variable-list (optional) : one or more struct variables.
Defining struct variables
Direct definition : define variables at the same time as the type, without a type name.
struct {
int a;
char b;
double c;
} s1;Indirect definition : declare the type first, then define variables.
// Declaration
struct SIMPLE {
int a;
char b;
double c;
};
// Definition
struct SIMPLE t1, t2[20], *t3;Note : The two examples define distinct types even if their member lists are identical.
Typedef alias : combine struct with typedef to create an alias.
typedef struct {
int a;
char b;
double c;
} Simple2; // Simple2 is an alias, not a variable.
Simple2 u1, u2[20], *u3;NOTE : Common convention uses *_s suffix for struct types and *_t for typedef aliases.
typedef struct student_s {
char *name;
int num;
int age;
char group;
float score;
} student_t;
student_t stu1;
sizeof(student_t);Initializing struct variables
Whole initialization (at definition):
#include <stdio.h>
/** Declare Books struct; define and initialize book variable */
struct Books {
char title[50];
char author[50];
char subject[100];
int id;
} book = {"is book", "fanguiju", "C", 123};
int main() {
printf("Book's title: %s
author: %s
subject: %s
id: %d
",
book.title, book.author, book.subject, book.id);
return 0;
}Member‑by‑member assignment using the . operator:
#include <stdio.h>
#include <string.h>
struct Books {
char title[50];
char author[50];
char subject[100];
int id;
};
int main() {
struct Books book1;
strcpy(book1.title, "C Programming");
strcpy(book1.author, "Nuha Ali");
strcpy(book1.subject, "C Programming Tutorial");
book1.id = 123;
printf("Book's title: %s
author: %s
subject: %s
id: %d
",
book1.title, book1.author, book1.subject, book1.id);
return 0;
}Struct pointer variables
Define a pointer to a struct: struct Books* struct_pointer; Assign the address of a struct variable: struct_pointer = &book1; Access members via ->: struct_pointer->title; Because a struct pointer holds an address, the . operator cannot be used; use -> instead.
#include <stdio.h>
#include <string.h>
struct Books {
char title[50];
char author[50];
char subject[100];
int id;
};
void printBook(struct Books* book) {
printf("Book's title: %s
author: %s
subject: %s
id: %d
",
book->title, book->author, book->subject, book->id);
}
int main() {
struct Books book1;
strcpy(book1.title, "C Programming");
strcpy(book1.author, "Nuha Ali");
strcpy(book1.subject, "C Programming Tutorial");
book1.id = 123;
printBook(&book1);
return 0;
}Struct members
Members can be of most data types, including other structs or pointers to the same struct type, enabling complex structures like linked lists or trees.
// Struct containing another struct
struct COMPLEX {
char string[100];
struct SIMPLE a;
};
// Struct containing a pointer to itself
struct NODE {
char string[100];
struct NODE *next_node;
};If two structs reference each other, one must be forward‑declared.
// Forward declaration of B
struct B;
// Definition of A containing a pointer to B
struct A {
struct B *partner;
// other members;
};
struct B {
struct A *partner;
// other members;
};Memory layout of structs
Struct members are stored contiguously, similar to arrays, but compilers may insert padding for alignment.
Padding can increase the total size; for example, a struct may occupy more bytes than the sum of its members.
Bit fields
When only a few bits are needed, bit fields allow packing multiple values into a single byte.
Bit fields are defined within a struct using a colon and width.
struct BitField {
type member_name : width;
...
};type : only int, unsigned int, or signed int are allowed.
member_name (optional) : identifier; unnamed fields serve as padding.
width : number of bits (max 8 for a byte); larger widths may be split by the compiler.
Example: a 2‑byte bit‑field struct.
struct bs {
int a:8;
int b:2;
int c:6;
} data;Unnamed fields can be used as padding.
struct bs {
unsigned a:4;
unsigned :4; // padding
unsigned b:4;
unsigned c:4;
}Bit‑field struct usage
#include <stdio.h>
int main() {
struct BS {
unsigned a:1;
unsigned b:3;
unsigned c:4;
};
struct BS bit;
struct BS *pbit;
bit.a = 1;
bit.b = 7;
bit.c = 15;
printf("%d, %d, %d
", bit.a, bit.b, bit.c);
pbit = &bit;
pbit->a = 0;
pbit->b &= 3;
pbit->c |= 1;
printf("%d, %d, %d
", pbit->a, pbit->b, pbit->c);
return 0;
}Output:
$ ./main
1, 7, 15
0, 3, 15Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
