我正在通过 CPP 学院 CLA 类(class) Material 进行第二次阅读,但我仍在为指针而苦苦挣扎。这是我试图理解的代码片段。我在下面的代码中评论了我的逻辑。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
// we are dereferencing pointer t of type float
// to = integer literal 1 + float pointer to memory location size
// of 2xfloats.
// I am guessing that this memory location will be filled with
// all zeroes or this assignment is invalid.
// This initial assignment is completely confusing me
// and rest of my logic/reading this snippet is probably wrong :D
float *t = 1 + (float *) malloc(sizeof(float) * sizeof(float));
printf("%f\n",*t); //0.00000
t--; //we move pointer to next zero in memory?!
printf("%f\n",*t); //0.00000
*t = 8.0; //we dereference pointer t and assign literal
//8.0. This will be [0] position
printf("%f\n",*t); //8.00000
t[1] = *t / 4.0; //we assign index position [1] to (*t (which
//is previously assigned to 8.0) divided by
//4.0 . This will assign t[1] to 2)
printf("%f\n",*t); //2.00000
t++; //we move pointer to next position [1] = 2
printf("%f\n",*t); //2.00000
t[-1] = *t / 2.0; //moving to position [0] and assigning it to 1
printf("%f\n",*t); //2.00000
free(--t);
return 0;
}
抱歉,我没有提到这不是工作计划的一部分。这是一长串简短的“技巧”片段,用于检查对 Material 的理解。我将仔细阅读您提供的详细答案。谢谢大家:D
最佳答案
<无缘无故的咆哮>
如果这个例子代表了 CPP 学院提供的类(class) Material 的整体质量,那么 I 非常强烈建议您在其他地方寻找您的教育和/或认证。
除非这个例子的标题是“如何不编写使用指针的代码”(在这种情况下它非常有效),否则这段代码很糟糕。它不仅令人困惑,而且充满了不良做法和未定义的行为。
无端吐槽>
让我们从明显的问题开始:
float *t = 1 + (float *) malloc(sizeof(float) * sizeof(float));
这 - 我不知道这应该说明什么,除了如何编写真正令人困惑的代码。
sizeof (float)
计算为 float
中的字节数,在大多数现代平台上将是 4 个字节。将该值平方意味着您为 N
留出了足够的空间。每个对象为 N
的对象字节宽 - IOW,如果 sizeof (float)
为 4,您有足够的空间容纳 4 个对象,而如果 sizeof (float)
是 8,你有足够的空间容纳 8 个对象。这是一种……不寻常的方式来指定你想要多少对象。我们现实世界中无聊的人就写
sizeof (float) * N
, 其中 N
是我们想要的对象的数量(实际上,我们写 sizeof *t * N
)。好的,所以我们为 N 个对象分配了足够的空间并返回指针 - 加 1?指针算术考虑了指向类型的大小,因此给指针加 1 表示“指向指向类型的下一个对象”(数组下标运算符
a[i]
定义为 *(a + i)
- 给定起始地址 a
,计算 i
之后的第 a
对象的地址并取消引用结果)。所以基本上,
t
开始指向动态缓冲区中的第二个对象。画出来,你会得到这样的东西: +---+
| |
+---+
t -> | |
+---+
| |
+---+
| |
+---+
malloc
不初始化动态缓冲区 - 缓冲区的内容是不确定的。不能保证驻留在该内存区域中的位模式对应于 0.00
的值。 .由于对象未初始化,因此尝试访问其值会导致未定义的行为 - 行printf("%f\n", *t);
可能导致
0.0000
的输出,或者它可能会导致一些其他随机值,或者您可能会遇到运行时错误,或者...该声明
t--;
从指针中减去 1,使其指向缓冲区中的第一个元素:
+---+
t -> | |
+---+
| |
+---+
| |
+---+
| |
+---+
*t = 8.0; //we dereference pointer t and assign literal
//8.0. This will be [0] position
printf("%f\n",*t); //8.00000
正确,虽然写起来会更清楚一些
t[0] = 8.0;
printf("%f\n", t[0]);
在处理您视为数组的内容时,最好使用数组下标表示法。
t[1] = *t / 4.0;
这段代码很痛苦。说真的,混合数组和指针表示法肯定会导致胃灼热。最好这样写
t[1] = t[0] / 4.0;
该声明
t++;
将指针加 1,使我们回到指向数组第二个元素的先前状态。
t[-1] = *t / 2.0;
这段代码值得一游。负指数是不好的juju。由于
t
现在指向数组的第二个元素,这不会爆炸,但它只是......只是......不要那样做。如果有人把这样的代码交给我审查,我会狠狠地把它踢回去,他们会感觉一个星期。说真的,不要那样做 .以下是该代码的编写方式:
#include <stdio.h>
#include <stdlib.h>
#define N 2 // assuming you only want 2 floats.
int main(void) {
/**
* Since the type of t is float *, the *expression* *t has
* type float - thus, sizeof *t == sizeof (float). Oh, and
* the cast on malloc is unnecessary, and under C89 will suppress
* a useful diagnostic if you forget to include stdlib.h.
*/
float *t = malloc( sizeof *t * N );
if ( t ) // ***ALWAYS*** check the result of malloc, calloc, or realloc
{
t[0] = 8.0;
printf( "%f\n", t[0] ); // 8.000
t[1] = t[0] / 4.0;
printf( "%f\n", t[1] ); //2.00000
t[0] = t[1] / 2.0;
printf( "%f\n", t[0]);
free(t); // release the memory
}
return 0;
}
请注意,您可以使用
calloc
而不是 realloc
如果要将分配的内存初始化为 all-bits-0:float *t = calloc( N, sizeof *t );
请注意,all-bits-0 不一定对应于
0.000
.
关于c - C 中解引用和引用指针的流程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49928986/