Appearance
C 标准库 - <stddef.h>
概述
<stddef.h> 头文件定义了几个标准类型和宏,这些定义在多个标准库头文件中都会用到。它提供了与指针、数组大小和偏移量相关的基本类型和宏。
标准类型
size_t
无符号整数类型,用于表示对象的大小。
c
#include <stdio.h>
#include <stddef.h>
int main() {
size_t size = sizeof(int);
printf("int 的大小: %zu\n", size);
return 0;
}ptrdiff_t
有符号整数类型,用于表示两个指针之间的差值。
c
#include <stdio.h>
#include <stddef.h>
int main() {
int arr[10];
int* ptr1 = &arr[0];
int* ptr2 = &arr[5];
ptrdiff_t diff = ptr2 - ptr1;
printf("指针差值: %td\n", diff);
return 0;
}wchar_t
宽字符类型,用于处理多字节字符集。
c
#include <stdio.h>
#include <stddef.h>
#include <wchar.h>
int main() {
wchar_t wc = L'A';
printf("宽字符: %lc\n", wc);
return 0;
}标准宏
NULL
空指针常量。
c
#include <stdio.h>
#include <stddef.h>
int main() {
int* ptr = NULL;
if (ptr == NULL) {
printf("指针是 NULL\n");
}
return 0;
}offsetof(type, member)
计算结构体成员的偏移量。
c
#include <stdio.h>
#include <stddef.h>
struct Person {
char name[50];
int age;
double height;
};
int main() {
printf("name 的偏移量: %zu\n", offsetof(struct Person, name));
printf("age 的偏移量: %zu\n", offsetof(struct Person, age));
printf("height 的偏移量: %zu\n", offsetof(struct Person, height));
return 0;
}实际应用示例
1. 内存分配
c
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
void* safe_malloc(size_t size) {
void* ptr = malloc(size);
if (ptr == NULL) {
fprintf(stderr, "内存分配失败\n");
exit(EXIT_FAILURE);
}
return ptr;
}
int main() {
size_t size = 100;
char* buffer = safe_malloc(size);
strcpy(buffer, "Hello, World!");
printf("%s\n", buffer);
free(buffer);
return 0;
}2. 数组遍历
c
#include <stdio.h>
#include <stddef.h>
void print_array(int* arr, size_t size) {
for (size_t i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
size_t size = sizeof(arr) / sizeof(arr[0]);
print_array(arr, size);
return 0;
}3. 指针运算
c
#include <stdio.h>
#include <stddef.h>
void pointer_arithmetic() {
int arr[] = {10, 20, 30, 40, 50};
int* ptr1 = &arr[1];
int* ptr2 = &arr[4];
ptrdiff_t diff = ptr2 - ptr1;
printf("ptr2 - ptr1 = %td\n", diff);
printf("ptr1 指向的值: %d\n", *ptr1);
printf("ptr2 指向的值: %d\n", *ptr2);
}
int main() {
pointer_arithmetic();
return 0;
}4. 结构体偏移量
c
#include <stdio.h>
#include <stddef.h>
#include <string.h>
struct Student {
int id;
char name[50];
double score;
};
void print_student_info(struct Student* student) {
printf("结构体大小: %zu\n", sizeof(struct Student));
printf("id 偏移量: %zu\n", offsetof(struct Student, id));
printf("name 偏移量: %zu\n", offsetof(struct Student, name));
printf("score 偏移量: %zu\n", offsetof(struct Student, score));
printf("\n学生信息:\n");
printf("ID: %d\n", student->id);
printf("姓名: %s\n", student->name);
printf("分数: %.2f\n", student->score);
}
int main() {
struct Student student = {1, "张三", 95.5};
print_student_info(&student);
return 0;
}5. 动态数组
c
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
typedef struct {
int* data;
size_t size;
size_t capacity;
} DynamicArray;
DynamicArray* create_array(size_t initial_capacity) {
DynamicArray* array = malloc(sizeof(DynamicArray));
if (array == NULL) {
return NULL;
}
array->data = malloc(initial_capacity * sizeof(int));
if (array->data == NULL) {
free(array);
return NULL;
}
array->size = 0;
array->capacity = initial_capacity;
return array;
}
void push_back(DynamicArray* array, int value) {
if (array->size >= array->capacity) {
array->capacity *= 2;
array->data = realloc(array->data, array->capacity * sizeof(int));
}
array->data[array->size++] = value;
}
void print_array(DynamicArray* array) {
for (size_t i = 0; i < array->size; i++) {
printf("%d ", array->data[i]);
}
printf("\n");
}
void free_array(DynamicArray* array) {
free(array->data);
free(array);
}
int main() {
DynamicArray* array = create_array(5);
if (array == NULL) {
return 1;
}
for (int i = 1; i <= 10; i++) {
push_back(array, i);
}
printf("数组内容: ");
print_array(array);
printf("大小: %zu\n", array->size);
printf("容量: %zu\n", array->capacity);
free_array(array);
return 0;
}6. 字符串长度
c
#include <stdio.h>
#include <stddef.h>
size_t my_strlen(const char* str) {
size_t len = 0;
while (str[len] != '\0') {
len++;
}
return len;
}
int main() {
const char* str = "Hello, World!";
size_t len = my_strlen(str);
printf("字符串: %s\n", str);
printf("长度: %zu\n", len);
return 0;
}7. 内存复制
c
#include <stdio.h>
#include <stddef.h>
#include <string.h>
void* my_memcpy(void* dest, const void* src, size_t n) {
unsigned char* d = (unsigned char*)dest;
const unsigned char* s = (const unsigned char*)src;
for (size_t i = 0; i < n; i++) {
d[i] = s[i];
}
return dest;
}
int main() {
char src[] = "Hello, World!";
char dest[20];
my_memcpy(dest, src, sizeof(src));
printf("源字符串: %s\n", src);
printf("目标字符串: %s\n", dest);
return 0;
}8. 结构体对齐
c
#include <stdio.h>
#include <stddef.h>
struct Aligned {
char c;
int i;
double d;
};
void print_alignment_info() {
printf("结构体对齐信息:\n");
printf("sizeof(struct Aligned): %zu\n", sizeof(struct Aligned));
printf("offsetof(c): %zu\n", offsetof(struct Aligned, c));
printf("offsetof(i): %zu\n", offsetof(struct Aligned, i));
printf("offsetof(d): %zu\n", offsetof(struct Aligned, d));
}
int main() {
print_alignment_info();
return 0;
}9. 指针比较
c
#include <stdio.h>
#include <stddef.h>
void compare_pointers() {
int arr[] = {10, 20, 30, 40, 50};
int* ptr1 = &arr[0];
int* ptr2 = &arr[2];
ptrdiff_t diff = ptr2 - ptr1;
printf("ptr1: %p\n", (void*)ptr1);
printf("ptr2: %p\n", (void*)ptr2);
printf("ptr2 - ptr1: %td\n", diff);
if (ptr1 < ptr2) {
printf("ptr1 在 ptr2 之前\n");
} else if (ptr1 > ptr2) {
printf("ptr1 在 ptr2 之后\n");
} else {
printf("ptr1 和 ptr2 相同\n");
}
}
int main() {
compare_pointers();
return 0;
}10. 链表节点
c
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
Node* create_node(int data) {
Node* node = malloc(sizeof(Node));
if (node == NULL) {
return NULL;
}
node->data = data;
node->next = NULL;
return node;
}
void print_list(Node* head) {
Node* current = head;
while (current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
}
void free_list(Node* head) {
Node* current = head;
while (current != NULL) {
Node* next = current->next;
free(current);
current = next;
}
}
int main() {
Node* head = create_node(1);
head->next = create_node(2);
head->next->next = create_node(3);
head->next->next->next = create_node(4);
head->next->next->next->next = create_node(5);
printf("链表: ");
print_list(head);
free_list(head);
return 0;
}注意事项
1. size_t 的使用
size_t 是无符号类型,避免与有符号类型混用。
c
#include <stdio.h>
#include <stddef.h>
void good_usage() {
size_t size = 10;
for (size_t i = 0; i < size; i++) {
printf("%zu ", i);
}
printf("\n");
}
void bad_usage() {
size_t size = 10;
for (int i = 0; i < size; i++) {
printf("%d ", i);
}
printf("\n");
}
int main() {
good_usage();
bad_usage();
return 0;
}2. NULL 的使用
使用 NULL 而不是 0 来表示空指针。
c
#include <stdio.h>
#include <stddef.h>
void good_usage() {
int* ptr = NULL;
if (ptr == NULL) {
printf("指针是 NULL\n");
}
}
void bad_usage() {
int* ptr = 0;
if (ptr == 0) {
printf("指针是 0\n");
}
}
int main() {
good_usage();
bad_usage();
return 0;
}3. offsetof 的限制
offsetof 只能用于标准布局的结构体。
c
#include <stdio.h>
#include <stddef.h>
struct StandardLayout {
int a;
char b;
};
struct NonStandardLayout {
int a;
char b;
virtual void foo();
};
int main() {
printf("标准布局偏移量: %zu\n", offsetof(struct StandardLayout, b));
return 0;
}4. ptrdiff_t 的范围
ptrdiff_t 可能无法表示非常大的指针差值。
c
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <limits.h>
void check_ptrdiff_range() {
size_t huge_size = SIZE_MAX / 2;
int* huge_array = malloc(huge_size * sizeof(int));
if (huge_array != NULL) {
int* ptr1 = &huge_array[0];
int* ptr2 = &huge_array[huge_size - 1];
ptrdiff_t diff = ptr2 - ptr1;
if (diff < 0) {
printf("指针差值溢出\n");
} else {
printf("指针差值: %td\n", diff);
}
free(huge_array);
} else {
printf("无法分配大数组\n");
}
}
int main() {
check_ptrdiff_range();
return 0;
}总结
<stddef.h> 提供的基本类型和宏是 C 语言编程的基础:
- size_t - 用于表示对象大小和数组索引
- ptrdiff_t - 用于表示指针之间的差值
- NULL - 表示空指针常量
- offsetof - 计算结构体成员的偏移量
记住:
- 使用
size_t表示大小和索引 - 使用
NULL表示空指针 ptrdiff_t可能有范围限制offsetof只适用于标准布局结构体