我正处于C指针学习阶段,我在网上寻找一些使用指针的代码,发现一个代码,现在我完全感到困惑。
int x, y;
char *p;
printf("Enter two integers:\n");
scanf("%d%d", &x, &y);
p = (char *)x;
while(--y)
p = &p[x];
P是x * y(乘积)的乘积,此代码可以正常工作。但是,如果我将指针类型更改为整数(int *p
和p= (int *)x)
,则会给我一些垃圾数字。
任何人都可以向我解释为什么在这种情况下使用“ char
”,为什么它可以正常工作,而不是对指针使用“ int
”。以及“ p = &p[x]
”处的情况(我不知道这行是如何工作的。)
答案 0 :(得分:0)
此代码依赖undefined behavior进行指针算术运算,以执行简单的乘法。
仅当指针指向有效对象并且该运算的结果也指向该对象内时,指针算术才被很好地定义。
第一行:
p = (char *)x;
采用用户给出的整数值x
并将其解释为指向char *
的指针,无论该值很可能不是指向有效位置,因此对它的任何算术运算都不确定行为。但是暂时,让我们假设编译器将执行算术运算,就好像指向有效对象一样,并且指针由单个整数值表示。
在循环的主体中,我们有:
p = &p[x];
这里的数组索引完全等于:
p = &(*(p + x));
解引用运算符和地址运算符互相抵消,所以等效于:
p = p + x;
添加到指针时,它实际上将给定值乘以所指向类型的大小,而不是直接添加到指针值。如果类型大于单个字节,这允许我们使用简单的算术指向给定数组元素的开始,而不是给定数组元素内的某些偏移量。在这种情况下,指向的类型为char
,因此x * sizeof(char)
被添加到p
的原始值中。而且由于sizeof(char)
的定义为1,因此p = p + x
只需将x
添加到p
的原始值中。
现在查看翻译后的正文的完整循环:
while (--y)
p = p + x;
将y
的值减小,然后检查减小的值是否为零。如果不是,则正文运行,将x
添加到p
。
假设y
为1。它递减为0,并且将值0用作while
循环的条件,该循环在布尔上下文中为false。因此不会输入循环,并且p
的值为x
。如果y
为2,则循环将输入一次,而p
将等于x + x
。如果y
为3,则循环进入两次,因此p
将为x + x + x
。
因此,这里的效果是p
在转换回整数时包含值x * y
。
如果将p
的类型更改为int *
,则得到不同值的原因是因为如前所述处理指针算法的方式。 sizeof(int)
最有可能是4,所以p = p + x
实际上是在x * 4
的原始值上加上p
,因此结果将大4倍。
不过,以上所有内容均取决于未定义的行为,因为p
并未指向有效的对象。它可以在某些系统和编译器上工作,但不能保证能工作。