C语言指针算术运算和结构体

我们应该只对数组使用指针算术运算,因为数组肯定分配在连续的内存块上,指针算术运算可以得到有效的偏移量。不过,不应该将它们用在结构体内,因为结构体的字段可能分配在不连续的内存区域。

下面这个结构体说明了这一点。为name字段分配10字节,之后是一个整数。然而,整数是对齐到4字节边界的,所以两个字段之间会有空隙。这类空隙在6.1节的“结构体的内存如何分配”中解释过了。

typedef struct _employee {
    char name[10];
    int age;
} Employee;

下面的代码试图用指针来访问结构体的age字段:

Employee employee;
// 初始化employee
char *ptr = employee.name;
ptr += sizeof(employee.name);

指针包含地址110,这是两个字段之间的2字节的地址,解引指针会把地址110处的4字节当做整数,如下图所示。

结构体填充示例

警告 误用对齐的指针可能会导致程序非正常终止或是取到错误数据。此外,如果编译器需要生成额外的机器码来弥补不恰当的对齐,那么指针访问也可能变慢。

即使结构体内的内存是连续的,用指针算术运算来访问结构体的字段也不是好做法。下面的结构体定义了由三个整数组成的Item,通常会将三个整数字段分配在连续的内存位置,不过也不一定:

typedef struct _item {
    int partNumber;
    int quantity;
    int binNumber;
}Item;

下面的代码片段声明了一个部件,然后用指针算术运算访问每个字段:

Item part = {12345, 35, 107};
int *pi = &part.partNumber;
printf("Part number: %d\n",*pi);
pi++;
printf("Quantity: %d\n",*pi);
pi++;
printf("Bin number: %d\n",*pi);

通常,输出就是我们所期望的那样,但也有例外。更好的办法是把每个字段赋给pi

int *pi = &part.partNumber;
printf("Part number: %d\n",*pi);
pi = &part.quantity;
printf("Quantity: %d\n",*pi);
pi = &part.binNumber;
printf("Bin number: %d\n",*pi);

更好的办法是根本不用指针,如下所示:

printf("Part number: %d\n",part.partNumber);
printf("Quantity: %d\n",part.quantity);
printf("Bin number: %d\n",part.binNumber);

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程