从结构数组中提取变量数组
Extract an array of variables from an array of structs
假设我将结构定义为
typedef struct worker{
char name[20];
int age;
} worker
然后我创建一个长度为 20 的数组,
worker *business;
business = malloc(20 * sizeof(worker));
是否有任何“自然”(即已经在语言中实现)的方式从这样的数组中获取“age”元素的子数组?
我正在考虑类似
的事情
business.age
其中 business.age
是 business
?
每个元素年龄的整数数组
typedef struct worker{
char name[20];
int age;
} worker
worker* business;
business = malloc(20 * sizeof(worker));
当你像上面那样分配结构数组时,age
的内存是不连续的,你不能像结构中的元素那样访问它。
/* error, business is an array */
business->age;
如果你想要连续的内存,你必须为 age
使用一个数组,为 name
使用一个数组而不是结构。
char** name = malloc(20 * 20 * sizeof(char));
int* age = malloc(20 * sizeof(int));
您的数组中结构的 age
字段未形成连续的内存区域。内存中的布局类似这样:
business[0] business[1]
[ 20 bytes of name | 4 bytes of age ][ 20 bytes of name | 4 bytes of age][ 20...
您的年龄由名称数组分隔。由于 C 中的数组必须是连续的内存区域,没有间隙,所以不可能只引用年龄的“数组”。但是,您可以使用 for 循环轻松遍历年龄或编写 function/define 宏来访问特定索引处的年龄:
int get_age_at_index(worker* arr, int idx) {
return arr[idx].age;
}
// OR
#define GET_AGE_AT_INDEX(arr, idx) (arr[idx].age)
这可能允许类似的语义来访问数组元素,如果这是您所追求的:
int my_age = get_age_at_index(business, 5);
// OR
int my_other_age = GET_AGE_AT_INDEX(business, 3);
如果您可以复制数据,您可以为 20 个整数分配一个数组并从每个结构复制年龄:
int ages[20] = { 0 };
for(int i; i < 20; i++) {
ages[i] = business[i].age;
}
编辑
通过做一些 hacky 指针运算,您可以非常接近您年龄段的数组访问语义。我不建议实际使用它,因为它可能不是 CPU 的最佳选择,而且不如以前的解决方案干净。我想在这里展示它作为一个特点。
当你有一个指向 C 中数组开头的指针时,比如 worker* business
并且你像数组一样对它进行索引
business[index]
下面发生的是指针在数组中“滑动”了一个偏移量。每个元素在数组中占用 sizeof(worker)
内存,因此“滑动”到下一个元素意味着将指针“增加”sizeof(worker)
。最后,business[index]
表示“计算值 business + index * sizeof(worker)
并访问该地址处的值,就好像它是一个结构 worker
”:
business points to the beginning of array:
[ worker struct 0 ][ worker struct 1 ][ worker struct 2 ]
^ ^ ^
0 * sizeof(worker) 1 * sizeof(worker) 2 * sizeof(worker) <-- offsets from the beginning of array
如果我们使指针等于第一个结构内存中 age
成员的地址,但将其转换为 worker*
:
worker* my_hacky_pointer = (worker*) &(business[0].age);
将它增加 1 实际上会将它移动 sizeof(worker)
,因为这是指针的类型。因此,它将移动到数组下一个元素的 age
成员。如果我们然后将此指针转换回 int
并取消引用它 *(int*) (my_hacky_pointer + 1)
我们将在索引 1.
处获得 age
字段的值
完整示例来源:
#include <stdio.h>
#include <stdlib.h>
typedef struct worker{
char name[20];
int age;
} worker;
int main() {
worker* business = malloc(20 * sizeof(worker));
business[0].age = 5;
business[1].age = 6;
business[2].age = 99;
business[3].age = 66;
business[4].age = 78;
worker* my_hacky_pointer = (worker*) &(business[0].age);
printf("my age: %d\n", *(int*) (my_hacky_pointer + 0)); // this prints 5
printf("my age: %d\n", *(int*) (my_hacky_pointer + 1)); // this prints 6
printf("my age: %d\n", *(int*) (my_hacky_pointer + 2)); // this prints 99
printf("my age: %d\n", *(int*) (my_hacky_pointer + 3)); // this prints 66
printf("my age: %d\n", *(int*) (my_hacky_pointer + 4)); // this prints 78
}
我建议不要在任何地方使用它,有更好的方法来获得相同的结果,在 CPU 上更清晰、更容易,但我认为有人会发现用指针算法可以实现的事情很有趣。
假设我将结构定义为
typedef struct worker{
char name[20];
int age;
} worker
然后我创建一个长度为 20 的数组,
worker *business;
business = malloc(20 * sizeof(worker));
是否有任何“自然”(即已经在语言中实现)的方式从这样的数组中获取“age”元素的子数组?
我正在考虑类似
的事情business.age
其中 business.age
是 business
?
typedef struct worker{
char name[20];
int age;
} worker
worker* business;
business = malloc(20 * sizeof(worker));
当你像上面那样分配结构数组时,age
的内存是不连续的,你不能像结构中的元素那样访问它。
/* error, business is an array */
business->age;
如果你想要连续的内存,你必须为 age
使用一个数组,为 name
使用一个数组而不是结构。
char** name = malloc(20 * 20 * sizeof(char));
int* age = malloc(20 * sizeof(int));
您的数组中结构的 age
字段未形成连续的内存区域。内存中的布局类似这样:
business[0] business[1]
[ 20 bytes of name | 4 bytes of age ][ 20 bytes of name | 4 bytes of age][ 20...
您的年龄由名称数组分隔。由于 C 中的数组必须是连续的内存区域,没有间隙,所以不可能只引用年龄的“数组”。但是,您可以使用 for 循环轻松遍历年龄或编写 function/define 宏来访问特定索引处的年龄:
int get_age_at_index(worker* arr, int idx) {
return arr[idx].age;
}
// OR
#define GET_AGE_AT_INDEX(arr, idx) (arr[idx].age)
这可能允许类似的语义来访问数组元素,如果这是您所追求的:
int my_age = get_age_at_index(business, 5);
// OR
int my_other_age = GET_AGE_AT_INDEX(business, 3);
如果您可以复制数据,您可以为 20 个整数分配一个数组并从每个结构复制年龄:
int ages[20] = { 0 };
for(int i; i < 20; i++) {
ages[i] = business[i].age;
}
编辑 通过做一些 hacky 指针运算,您可以非常接近您年龄段的数组访问语义。我不建议实际使用它,因为它可能不是 CPU 的最佳选择,而且不如以前的解决方案干净。我想在这里展示它作为一个特点。
当你有一个指向 C 中数组开头的指针时,比如 worker* business
并且你像数组一样对它进行索引
business[index]
下面发生的是指针在数组中“滑动”了一个偏移量。每个元素在数组中占用 sizeof(worker)
内存,因此“滑动”到下一个元素意味着将指针“增加”sizeof(worker)
。最后,business[index]
表示“计算值 business + index * sizeof(worker)
并访问该地址处的值,就好像它是一个结构 worker
”:
business points to the beginning of array:
[ worker struct 0 ][ worker struct 1 ][ worker struct 2 ]
^ ^ ^
0 * sizeof(worker) 1 * sizeof(worker) 2 * sizeof(worker) <-- offsets from the beginning of array
如果我们使指针等于第一个结构内存中 age
成员的地址,但将其转换为 worker*
:
worker* my_hacky_pointer = (worker*) &(business[0].age);
将它增加 1 实际上会将它移动 sizeof(worker)
,因为这是指针的类型。因此,它将移动到数组下一个元素的 age
成员。如果我们然后将此指针转换回 int
并取消引用它 *(int*) (my_hacky_pointer + 1)
我们将在索引 1.
age
字段的值
完整示例来源:
#include <stdio.h>
#include <stdlib.h>
typedef struct worker{
char name[20];
int age;
} worker;
int main() {
worker* business = malloc(20 * sizeof(worker));
business[0].age = 5;
business[1].age = 6;
business[2].age = 99;
business[3].age = 66;
business[4].age = 78;
worker* my_hacky_pointer = (worker*) &(business[0].age);
printf("my age: %d\n", *(int*) (my_hacky_pointer + 0)); // this prints 5
printf("my age: %d\n", *(int*) (my_hacky_pointer + 1)); // this prints 6
printf("my age: %d\n", *(int*) (my_hacky_pointer + 2)); // this prints 99
printf("my age: %d\n", *(int*) (my_hacky_pointer + 3)); // this prints 66
printf("my age: %d\n", *(int*) (my_hacky_pointer + 4)); // this prints 78
}
我建议不要在任何地方使用它,有更好的方法来获得相同的结果,在 CPU 上更清晰、更容易,但我认为有人会发现用指针算法可以实现的事情很有趣。