我正在通过CPP学院的CLA课程材料进行第二次阅读,我仍然在努力寻找指针。这是我想要了解的代码片段。我在下面的代码中评论了我的逻辑。
#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;
}
道歉我没有提到这不是工作计划的一部分。这是一长串的短片&#34;技巧&#34;片段以检查对材料的理解。我将详细介绍您提供的答案。谢谢大家:D
答案 0 :(得分:2)
&lt; gratuitous rant&gt;
如果这个例子代表了CPP研究所提供的课程材料的整体质量,那么我非常强烈建议您到其他地方寻找您的教育和/或认证。
除非这个例子标题为&#34;如何 NOT 编写使用指针的代码&#34; (在这种情况下,非常有效),此代码糟糕。它不仅令人困惑,还充满了糟糕的做法和不确定的行为。
&lt; / gratuitous rant&gt;
让我们从明显的问题开始:
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表示&#34;指向指向类型的下一个对象&#34; (数组下标运算符a[i]
定义为*(a + i)
- 给定起始地址a
,计算i
&#39}的地址。在a
之后的对象并取消引用结果)。
基本上,t
开始指向动态缓冲区中的第二个对象。把它拿出来,你得到这样的东西:
+---+
| |
+---+
t -> | |
+---+
| |
+---+
| |
+---+
malloc
未初始化动态缓冲区 - 缓冲区的内容为 indeterminate 。不能保证驻留在该存储区中的位模式对应于0.00
的值。由于对象未初始化,尝试访问其值会导致未定义的行为 - 行
printf("%f\n", *t);
可能导致0.0000
的输出,或者它可能会导致其他一些随机值,或者您可能会遇到运行时错误,或者......
声明
t--;
从指针中减去1,使其指向缓冲区中的 first 元素:
+---+
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;
这段代码非常适合paddlin&#39;。负指数是坏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;
}
请注意,如果您希望将分配的内存初始化为all-bits-0,则可以使用calloc
而不是realloc
:
float *t = calloc( N, sizeof *t );
请注意,所有位-0并不一定与0.000
对应。
答案 1 :(得分:1)
几乎所有的假设似乎都是正确的; 只有第一个“我猜这个内存位置将被所有零填充或者这个赋值无效”可能会更具体一点:
float *t = 1 + (float *) malloc(sizeof(float) * sizeof(float));
为几个浮点值分配内存;实际上sizeof(float) * sizeof(float)
很少有意义,因为可用浮点值的数量取决于浮点数的大小。它不会使用0初始化内存,因此内存未初始化。并且 - 这是现在最重要的事情 - 像printf("%f\n",*t);
一样访问未初始化的值会产生未定义的行为。允许编译器执行任何操作,甚至完全忽略该语句。
所以你实际上写了
float *t = 1 + (float *) calloc(sizeof(float), 4);
calloc
将内存初始化为0
,并且浮动数量更具确定性。
答案 2 :(得分:0)
第一个printf("%f\n",*t);
会导致undefined behaviour读取未初始化的内存位置并将结果传递给标准库函数。
如链接中所述,这意味着程序的整个输出毫无意义。甚至没有必要阅读超出这一行的代码。