c - C 中解引用和引用指针的流程

标签 c pointers memory-management

我正在通过 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/

相关文章:

r - 节省内存的 scale() 函数

c - 为什么这2个指针地址没有区别?

c - 下面的代码是什么意思/做什么?

c++ - cmake 和 2 个库

c - mac 操作系统 x 10.6 : syslog() EXC_BAD_ACCESS

c - 结构体指针作为返回类型

c - 错误 : expression must be a modifiable l value

iPhone 内存管理

ios - 为什么我在尝试显示 GKPeerPicker Controller 时崩溃并说 EXC-BAD ACCESS(ARC 已打开)

c - 我下面使用指针获取字符串长度的代码有什么问题?