【问题标题】:Dynamic allocation and pointers动态分配和指针
【发布时间】:2014-02-14 14:43:18
【问题描述】:
int *ptr;      
ptr=(int *)malloc(sizeof(int)*2);       
ptr=100;    /*What will happen if I put an asterisk(*) indicating *ptr=100? */            
ptr++;        
printf("ptr=%d",*ptr);         
free(ptr);       

所以,我希望指针递增。我为指针分配了 4(2*2) 的大小。但我无法理解指针如何仅增加 2。如果我在第 3 行加上一个星号,那就是 *ptr=100;它显示了其他东西。

【问题讨论】:

  • Please don't cast the return value of malloc() in C。除了%p 和转换为void * 之外,不要打印指针。
  • 公平地说,这可能不是故意的,他在他的printf() 调用中取消引用该指针,所以%d 在这里是正确的,%p 不是。格式字符串的内容似乎表明希望打印 ptr 的值,而不是它所指向的值,但很难确定。

标签: c pointers dynamic-allocation


【解决方案1】:

如果您有int * ptr,则ptr++ 将指针增加单个int 的大小。如果int 在您的平台上是两个字节,这就是它增加两个的原因。

*ptr = 100 会将值100 存储在ptr 指向的int 中,即您通过malloc() 调用分配的两个int 中的第一个。

ptr = 100 将尝试将内存地址100 分配给ptr,这几乎肯定不是您想要的,因为您会丢失对刚刚malloc()ed 的内存的引用,以及在内存位置100 可能对您没有意义或无法访问。

就目前而言,如果您先执行*ptr = 100,然后执行ptr++,您的printf() 调用将导致未定义的行为,因为您会增加指针以指向未初始化的内存(即第二个您使用 malloc() 调用分配的两个 ints),然后您尝试输出其内容。

另一方面,(*ptr)++ 会将100 的值增加到101,保持ptr 的值不变,您的printf() 调用会很好,并输出101。您分配的两个 ints 中的第二个仍将保持未初始化状态,但如果您不尝试访问它也没问题。

另外,不要将malloc()的返回值转换为ptr=(int *)malloc(sizeof(int)*2),应该是ptr=malloc(sizeof(int)*2),甚至更好,ptr = malloc(sizeof(*ptr) * 2)

【讨论】:

  • ... 甚至 ptr = malloc(2 * sizeof *ptr);,在我的世界里。 :)
  • @unwind 是的,在这种情况下,我属于“更喜欢添加括号”阵营,尽管正如你所说,它们是不必要的。
  • @PaulGriffiths : ptr = malloc(sizeof(*ptr) * 2); 未定义,因为 OP 没有通过指针将任何整数存储到地址指针。所以它可能是任何垃圾值。
  • @kevingomes:这里不是未定义的行为。 sizeof 不计算其表达式。
  • @PaulGriffiths:为什么?
【解决方案2】:

试试这个:

int *ptr;
ptr = malloc(2 * sizeof *ptr);
printf("ptr = %p.\n", (void *) ptr); // Examine pointer before increment.
ptr++;
printf("ptr = %p.\n", (void *) ptr); // Examine pointer after increment.

您将看到ptr 的值增加了int 中的字节数。 C 语言自动以指向元素为单位进行指针运算。因此,在 C 中,int 指针的单个增量在机器级别上变成了 int 字节数的增量。


注意事项

%p 是打印指针时使用的正确说明符,而不是 %d。此外,指针必须强制转换为void *const void *

ptr = malloc(2 * sizeof *ptr); 是比原始代码更简洁的内存分配和指针分配方式,因为:

  • 如果您更改了ptr 的类型,使用sizeof *ptr 会使代码自动适应。不必在两个地方更改类型(声明ptr 和调用malloc 的地方),一个更改就足够了。这样可以减少出错的机会。
  • malloc 不需要强制转换为目标类型。它返回一个void *,C 将自动将其转换为分配的目标类型而不会产生任何抱怨。 (C++ 是不同的。)如果你强制转换它仍然可以工作,但这会掩盖另一个问题:如果你不小心没有声明malloc(因为没有包含<stdlib.h>,并在旧版本的 C 中编译, malloc 将被隐式声明为返回 int,并且强制转换将掩盖错误。如果不进行强制转换,则表达式会在发生这种情况时产生警告消息。

【讨论】:

    【解决方案3】:

    这一行将指针中的地址值更改为一些废话(100不会是任何有效地址):

    ptr=100;
    

    然后你将指针递增到100 + sizeof(int),因为指针的类型为int*,它会自动将地址递增字节数以获取ptr指向的下一个整数。

    在下一行,您取消引用无效指针,因此您的代码应该崩溃,但如果您的指针具有有效地址,则该命令是可以的:

    printf("ptr=%d",*ptr);
    

    要修复您的代码,不要更改指针本身,而是更改数据:

    int *ptr;      
    ptr=(int *)malloc(sizeof(int)*2);       
    *ptr=123;    /*What will happen if I put an asterisk(*) indicating *ptr=100? */            
    printf("ptr=%d",*ptr);
    ptr++;
    *ptr=234;     
    printf("ptr+1=%d",*ptr);
    // you can set or get your data also this way:
    ptr[0] = 333;
    ptr[1] = 444;
    printf("ptr[0]=%d",ptr[0]);
    printf("ptr[1]=%d",ptr[1]);
    free(ptr);
    

    【讨论】:

      【解决方案4】:

      首先你需要了解的是一个POINTER指向ADDRESS,当你将100分配给ptr时,这意味着你的指针ptr现在指向地址为100的内存位置。

      其次,指针运算取决于指针的类型,在您的情况下 ptr 是指向整数的指针。所以当你增加ptr时,这意味着它将跳转到下一个整数的内存位置。所以,ptr 增加 2(你的平台上一个 int 占用的内存)

      【讨论】:

        【解决方案5】:

        简单点

        ptr=100;
        

        通过这种方式,您试图将int 存储为指向指针的地址,这是无稽之谈。
        换句话说,您试图使指针ptr 指向地址100,这不是地址。

        但是通过

        *ptr=100;
        

        您正在尝试将值100 存储到ptr 指向的地址,这是有效的。

        还有

        ptr++;
        

        意味着现在ptr 指向ptr+4 或(ptr+2 for 16 bit compiler like tc)地址。

        同样对于您的特定代码,您只是更改和递增ptr 指向的地址,但您没有在ptr 指向的地址存储任何值。
        所以你的代码会打印垃圾值或者它也可能因为100不是一个有效的地址而崩溃。

        你也应该这样做

        ptr=(int*)100;
        

        它会删除

        warning: assignment makes pointer from integer without a cast [enabled by default]
        

        但它仍然是未定义的行为。

        【讨论】:

        • 将整数转换为指针是实现定义的行为,而不是未定义的行为。它可能对各种系统都有意义。
        • @PaulGriffiths : undefined 我的意思是任何值都可以存储在ptr指向的地址,但行为是定义的。
        • 不一定 - 如果您在一个系统上工作,该系统在内存位置 100 存储了一些有意义的东西,那么结果将由实现明确定义。
        • @PaulGriffiths :但用户不会意识到该值。
        • 如果他取消引用指针,他就不会。例如,在旧的微型计算机上,为操作系统 API 调用或其他系统提供的值的入口点位置硬编码内存地址是很常见的。地址将列在计算机手册中,通过手动使用地址来显式访问这些内存位置是正常的。例如,如今同样的事情可以在嵌入式系统上运行。
        猜你喜欢
        • 1970-01-01
        • 2019-07-12
        • 2015-02-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多