仅使用指针算法在结构成员之间移动
Move between members of a structure using only pointer arithmetic
参考下面的代码,我可以这样向一个结构体的成员中插入数据:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct user {
int id;
char username[20];
char password[20];
};
int main(void) {
struct user *p;
p = malloc(sizeof(struct user));
p->id = 27;
strcpy(p->username, "roberto");
strcpy(p->password, "P4_4t4r");
printf("Id = %d\n", p->id);
printf("Username = %s\n", p->username);
printf("Password = %s\n", p->password);
return 0;
}
上面提到的程序可以运行。现在,我想尝试使用指针算法,既用于赋值又用于显示结构成员,我想我会按如下方式进行:
#include <stdlib.h>
#include <stdio.h>
struct user {
int id;
char username[20];
char password[20];
};
int main(void) {
struct user *p;
p = malloc(sizeof(struct user));
*(int*)p = 27; // id = 27
p += 4; // int is 4 bytes, so let's move 4 bytes ...
*(char*)p = 'r';
*(char*)++p = 'o';
*(char*)++p = 'b';
*(char*)++p = 'e';
*(char*)++p = 'r';
*(char*)++p = 't';
*(char*)++p = 'o';
*(char*)++p = '[=11=]';
p += 13;
*(char*)p = 'P';
*(char*)++p = '4';
*(char*)++p = '_';
*(char*)++p = '4';
*(char*)++p = 't';
*(char*)++p = '4';
*(char*)++p = 'r';
*(char*)++p = '[=11=]';
p -= 31; // I put the pointer back to the first byte of the memory block
// Output
printf("Id = ");
printf("%d\n", *(int*)p);
p += 4;
printf("Username = ");
printf("%c", *(char*)p); // r
printf("%c", *(char*)++p); // o
printf("%c", *(char*)++p); // b
printf("%c", *(char*)++p); // e
printf("%c", *(char*)++p); // r
printf("%c", *(char*)++p); // t
printf("%c\n", *(char*)++p); // o
++p; // [=11=]
p += 13;
printf("Password = ");
printf("%c", *(char*)p); // P
printf("%c", *(char*)++p); // 4
printf("%c", *(char*)++p); // _
printf("%c", *(char*)++p); // 4
printf("%c", *(char*)++p); // t
printf("%c", *(char*)++p); // 4
printf("%c\n", *(char*)++p); // r
++p; // [=11=]
printf("\n");
p -= 31; // I put the pointer back to the first byte of the memory block
return 0;
}
我从两个来源的比较中了解到右箭头选择(->)运算符非常有用。
现在我想到了使用指针的算法将值分配给结构的成员,并使用右箭头选择 (->) 运算符显示它们的内容,如下所示:
#include <stdlib.h>
#include <stdio.h>
struct user {
int id;
char username[20];
char password[20];
};
int main(void) {
struct user *p;
p = malloc(sizeof(struct user));
*(int*)p = 27;
p += 4;
*(char*)p = 'r';
*(char*)++p = 'o';
*(char*)++p = 'b';
*(char*)++p = 'e';
*(char*)++p = 'r';
*(char*)++p = 't';
*(char*)++p = 'o';
*(char*)++p = '[=12=]';
p += 13;
*(char*)p = 'P';
*(char*)++p = '4';
*(char*)++p = '_';
*(char*)++p = '4';
*(char*)++p = 't';
*(char*)++p = '4';
*(char*)++p = 'r';
*(char*)++p = '[=12=]';
p -= 31;
printf("Id = %d\n", p->id);
printf("Username = %s\n", p->username);
printf("Password = %s\n", p->password);
return 0;
}
但在后一种情况下,我得到了这个结果:
Id = 27
Username =
Password =
谁能告诉我哪里错了?
递增指向结构的指针会将其移动到刚好超过结构的末尾。
想象一个数组,其中每个元素都是一个 struct user
。如果 p
声明为 struct user *p
并指向该数组的开头,p += 4
将使其指向该数组中的第五个元素(struct user
)。
这意味着在你执行的时候
*(char*)p = 'r';
*(char*)++p = 'o';
...
您超出了您分配的结构的范围。
如果您希望指针增加较小类型的大小,您需要先将其转换为该类型的指针:
unsigned char *byteptr = (unsigned char *)p;
然后使用 byteptr
执行写入。
这里还有一个隐藏的问题是,编译器和硬件架构的不同组合导致了不同的alignment requirements。这意味着编译器可能会在结构字段之间插入填充。
使用指针运算来计算指向结构字段的指针是个坏主意,因为您需要知道填充是什么。最好的办法是直接使用 ->
(在结构指针上)或 .
(在结构值上)来引用结构字段。
你在这里做的是一个很好的学习练习。您可能应该使用 strncpy
而不是 strcpy
.
参考下面的代码,我可以这样向一个结构体的成员中插入数据:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct user {
int id;
char username[20];
char password[20];
};
int main(void) {
struct user *p;
p = malloc(sizeof(struct user));
p->id = 27;
strcpy(p->username, "roberto");
strcpy(p->password, "P4_4t4r");
printf("Id = %d\n", p->id);
printf("Username = %s\n", p->username);
printf("Password = %s\n", p->password);
return 0;
}
上面提到的程序可以运行。现在,我想尝试使用指针算法,既用于赋值又用于显示结构成员,我想我会按如下方式进行:
#include <stdlib.h>
#include <stdio.h>
struct user {
int id;
char username[20];
char password[20];
};
int main(void) {
struct user *p;
p = malloc(sizeof(struct user));
*(int*)p = 27; // id = 27
p += 4; // int is 4 bytes, so let's move 4 bytes ...
*(char*)p = 'r';
*(char*)++p = 'o';
*(char*)++p = 'b';
*(char*)++p = 'e';
*(char*)++p = 'r';
*(char*)++p = 't';
*(char*)++p = 'o';
*(char*)++p = '[=11=]';
p += 13;
*(char*)p = 'P';
*(char*)++p = '4';
*(char*)++p = '_';
*(char*)++p = '4';
*(char*)++p = 't';
*(char*)++p = '4';
*(char*)++p = 'r';
*(char*)++p = '[=11=]';
p -= 31; // I put the pointer back to the first byte of the memory block
// Output
printf("Id = ");
printf("%d\n", *(int*)p);
p += 4;
printf("Username = ");
printf("%c", *(char*)p); // r
printf("%c", *(char*)++p); // o
printf("%c", *(char*)++p); // b
printf("%c", *(char*)++p); // e
printf("%c", *(char*)++p); // r
printf("%c", *(char*)++p); // t
printf("%c\n", *(char*)++p); // o
++p; // [=11=]
p += 13;
printf("Password = ");
printf("%c", *(char*)p); // P
printf("%c", *(char*)++p); // 4
printf("%c", *(char*)++p); // _
printf("%c", *(char*)++p); // 4
printf("%c", *(char*)++p); // t
printf("%c", *(char*)++p); // 4
printf("%c\n", *(char*)++p); // r
++p; // [=11=]
printf("\n");
p -= 31; // I put the pointer back to the first byte of the memory block
return 0;
}
我从两个来源的比较中了解到右箭头选择(->)运算符非常有用。 现在我想到了使用指针的算法将值分配给结构的成员,并使用右箭头选择 (->) 运算符显示它们的内容,如下所示:
#include <stdlib.h>
#include <stdio.h>
struct user {
int id;
char username[20];
char password[20];
};
int main(void) {
struct user *p;
p = malloc(sizeof(struct user));
*(int*)p = 27;
p += 4;
*(char*)p = 'r';
*(char*)++p = 'o';
*(char*)++p = 'b';
*(char*)++p = 'e';
*(char*)++p = 'r';
*(char*)++p = 't';
*(char*)++p = 'o';
*(char*)++p = '[=12=]';
p += 13;
*(char*)p = 'P';
*(char*)++p = '4';
*(char*)++p = '_';
*(char*)++p = '4';
*(char*)++p = 't';
*(char*)++p = '4';
*(char*)++p = 'r';
*(char*)++p = '[=12=]';
p -= 31;
printf("Id = %d\n", p->id);
printf("Username = %s\n", p->username);
printf("Password = %s\n", p->password);
return 0;
}
但在后一种情况下,我得到了这个结果:
Id = 27
Username =
Password =
谁能告诉我哪里错了?
递增指向结构的指针会将其移动到刚好超过结构的末尾。
想象一个数组,其中每个元素都是一个 struct user
。如果 p
声明为 struct user *p
并指向该数组的开头,p += 4
将使其指向该数组中的第五个元素(struct user
)。
这意味着在你执行的时候
*(char*)p = 'r';
*(char*)++p = 'o';
...
您超出了您分配的结构的范围。
如果您希望指针增加较小类型的大小,您需要先将其转换为该类型的指针:
unsigned char *byteptr = (unsigned char *)p;
然后使用 byteptr
执行写入。
这里还有一个隐藏的问题是,编译器和硬件架构的不同组合导致了不同的alignment requirements。这意味着编译器可能会在结构字段之间插入填充。
使用指针运算来计算指向结构字段的指针是个坏主意,因为您需要知道填充是什么。最好的办法是直接使用 ->
(在结构指针上)或 .
(在结构值上)来引用结构字段。
你在这里做的是一个很好的学习练习。您可能应该使用 strncpy
而不是 strcpy
.