只使用指针运算在结构的成员之间移动。

问题描述 投票:1回答:1

参考下面的代码,我可以用这种方式将数据插入到结构的成员中。

#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 = '\0';

    p += 13;

    *(char*)p = 'P';
    *(char*)++p = '4';
    *(char*)++p = '_';
    *(char*)++p = '4';
    *(char*)++p = 't';
    *(char*)++p = '4';
    *(char*)++p = 'r';
    *(char*)++p = '\0';


    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;                            // \0

    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;                            // \0

    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 = '\0';

    p += 13;

    *(char*)p = 'P';
    *(char*)++p = '4';
    *(char*)++p = '_';
    *(char*)++p = '4';
    *(char*)++p = 't';
    *(char*)++p = '4';
    *(char*)++p = 'r';
    *(char*)++p = '\0';

    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 = 

谁能告诉我我错在哪里?

c struct malloc pointer-arithmetic
1个回答
2
投票

对一个结构的指针进行递增,会将其移动到结构的末端。

想象一个数组,其中每个元素是一个 struct user. 如果 p 被宣布为 struct user *p 并指向该数组的起点。p += 4 将使其指向第五个要素(a struct user)的数组中。

这意味着,当你在执行

*(char*)p = 'r';
*(char*)++p = 'o';
...

你已经超出了你分配的结构体的范围。

如果你想让指针按较小类型的大小递增,你需要首先将其投向该类型的指针。

unsigned char *byteptr = (unsigned char *)p;

然后使用 byteptr 来执行你的写入。

另一个隐藏的问题是,编译器和硬件架构的不同组合会导致不同的 排列要求. 这意味着编译器可能会在结构字段之间插入padding。

使用指针运算来计算结构字段的指针是个坏主意,因为你需要知道这些填充物是什么。你最好的办法是直接使用 -> (在结构指针上)或 . (在一个结构值上)。

不过你在这里做的是一个很好的学习练习。你可能应该使用 strncpy 而不是 strcpy.

© www.soinside.com 2019 - 2024. All rights reserved.