C编程指针预先修复后修复

时间:2015-11-13 03:32:59

标签: c pointers

我在尝试理解C编程中的指针时遇到了一些问题。

struct student {
int age;
char *name;
};

int main()
{
    struct student b[3] = { 18, "Peter", 19, "Mary", 20, "John" };
    struct student *p = b;

    printf("%d\n", ++p->age);
    printf("%s\n", (*p).name);
    printf("%c\n", *p->name - 1);
    printf("%c\n", *++p->name);
    printf("%c\n", *p++->name);
    printf("%c\n", *(++p)->name);
    return 0;
}

我从visual studio获得的输出是:

19
Peter
0
e
e
J

对于前三行我理解它是如何工作的。但是,在*++p->name它是怎么来的?'我认为指针已经指向玛丽,它应该是' a'以下应该是' a'以及它的后期修复。然后就*(++p)->name而言,让我们说上一行让我回过头来,它是如何跳过玛丽并打印出来的。'。

我的任务是在没有运行程序的情况下将输出写在纸上,所以我想知道原因。提前谢谢。

3 个答案:

答案 0 :(得分:1)

对于寻址操作"从后缀开始,继续前缀,并从里到外读取两组。"除非parens覆盖优先级,否则它们与其他运算符的工作方式相同。

因此*x->y被解释为将x视为指向struct的->指针,查找其y成员,然后将其视为指针{{1}取消引用它以获得最终值。

相反,*被解释为将(*x)->y视为指向pointef结构的指针,x取消引用它以获取指向struct的指针,然后*检索->成员。

请注意,[]也是后缀运算符。所以y检索第三个指向结构的指针,从中获取y,然后解除引用。

__有用提示:_ C声明的语法和优先级与C寻址完全相同。所以*x[3]->y是一个指向四个整数数组的指针,而int (*x)[4];是一个由4个指针组成的数组。

(多年前我为C声明编写了一个简单的递归下降解析器,它会将它们转换成这种类型的短语。正如任何老派黑客所说的那样,我称之为C EXplainer,或CEX,明显的发音。)

答案 1 :(得分:0)

*++p->name相当于*(++(p->name))

此时,p仍然指向b的第一个元素,因此其内容为{ 18, "Peter" }

它接受name指针,对其应用前缀增量,表达式求值为指向"Peter"的第二个字符的指针。最后,解除引用运算符给出了字符'e'

*(++p)->namep指向b的最后一个元素(在增量之后),因此其内容为{ 20, "John" }

它会使用name指针并取消引用它,以便为"John"提供'J'的第一个字符。

修改:在每个printf之后打印指针值可能会对您有所帮助,以帮助您了解输出。

答案 2 :(得分:0)

struct student b[3] = { 18, "Peter", 19, "Mary", 20, "John" };

创建一个struct student数组,其中包含三个元素,这些元素取决于编译器和填充,将具有sizeof 12-16个字符(x86_64)或8-16个字符(x86),由{组成{1}}(int)和4-bytes(char *)(x86上的4个字节)并且将具有类似的内存布局(例如用途):

8-bytes

在内存中创建单个字符串文字( int char* +----+--------+----+--------+----+--------+ |age |name* |age |name* |age |name* | +----+--------+----+--------+----+--------+ ^ p ),并将指向每个字符串文字的指针存储为结构的各个元素中的"Peter", "Mary", "John"

使用name运算符时,它是结构的解引用。使用->上的预增量运算符,可以获得数组p->age中的下一个age元素,但指针地址b保持不变:

p

取消引用printf("%d\n", ++p->age); +----+--------+----+--------+----+--------+ |age |name* |age |name* |age |name* | +----+--------+----+--------+----+--------+ ^ ^ p ++p->age 19 并使用p(点)运算符,打印与'.'中当前元素关联的名称:

b

当您从printf("%s\n", (*p).name); Peter 中减去1时,您正在按*p->name递减字符指针,这会让您在 no-mans-land 中的内存中的地址处在字符串文字“彼得”之前的某个地方。

1

当你取消引用然后预增量时,(你正在递增指针printf("%c\n", *p->name - 1); +----+--------+----+--------+----+--------+ |age |name* |age |name* |age |name* | +----+--------+----+--------+----+--------+ ^ \ p Peter (string literal in memory) ^ p->name - 1 0 )你在字符串文字“Peter”中向前移动一个字符:

p->name

当您下次取消引用,然后进行后递增时,您将打印相同的字符,然后将指针前进到printf("%c\n", *++p->name); +----+--------+----+--------+----+--------+ |age |name* |age |name* |age |name* | +----+--------+----+--------+----+--------+ ^ \ p Peter ^ ++p->name e 中的第二个元素:

b

最后通过运算符优先级,您预先递增指针(将指针前进到printf("%c\n", *p++->name); +----+--------+----+--------+----+--------+ |age |name* |age |name* |age |name* | +----+--------+----+--------+----+--------+ ^ \ p Peter ^ p->name e +----+--------+----+--------+----+--------+ |age |name* |age |name* |age |name* | +----+--------+----+--------+----+--------+ ^ p 中的第三个元素),然后将指针b指向p->name

J