【问题标题】:How can I move to a pointer position directly without using the ++ operator?如何在不使用 ++ 运算符的情况下直接移动到指针位置?
【发布时间】:2018-05-27 01:29:35
【问题描述】:

我正在使用指向结构的指针。我想知道是否可以在不使用 ++ 运算符的情况下直接移动到特定位置。

#include <stdio.h>
#include <stdlib.h>

#define ARRAY_SIZE 10

struct dummy{
    int id;
    char buffer[10];
};

typedef struct dummy dummy_struct;

int main()
{
    int i=0;
    dummy_struct *ds = malloc(sizeof(dummy_struct)*ARRAY_SIZE);
    dummy_struct *iterator = ds;

    for(i=0;i<ARRAY_SIZE;i++)
    {
        iterator->id = i;
        sprintf(iterator->buffer,"%d",i);
        iterator++;
    }

    iterator = ds;

    for(i=0;i<ARRAY_SIZE;i++)
    {
        printf("%d:%s:%p\n",iterator->id,iterator->buffer,iterator);
        iterator++;
    }

    // I want to access directly to 5th position
    iterator = ds + (sizeof(dummy_struct)*5);
    printf("5th position %d:%s:%p\n",iterator->id,iterator->buffer,iterator);

    return 0;
}

此声明

iterator = ds + (sizeof(dummy_struct)*5);

不工作。我会很感激任何建议。

【问题讨论】:

  • 对于任何指针(或数组)p 和索引i,表达式p[i] 完全等于*(p + i)。指针算法只是索引“数组”的一种奇特方式。
  • ... 或者更确切地说,p[i] 只是 *(p + i) 的精美语法糖(原样)。
  • 简单写iterator = &amp;ds[5];
  • x++ 本质上是x=x+1,而不是x=x+sizeof(something)
  • @Dukeling x++ 确实与x = x + 1 相同,但如果您检查指针的原始值,它确实具有将x 推进sizeof *x 字节的效果。

标签: c pointers operators pointer-arithmetic


【解决方案1】:

好吧,指针算术尊重数据类型!!

iterator = ds + 5;

将完成工作。

更详细地说,上面的表达式将通过移动 5 次产生一个指针,乘以 ds 的类型大小,以字节为单位。这与&amp;(ds[5]) 相同。

为了完整起见,解释为什么iterator = ds + (sizeof(dummy_struct)*5); 是错误的,在这里,您实际上是在尝试将指针移动到索引为(sizeof(dummy_struct)*5 的元素,这超出了界限。请注意,这会调用undefined behavior!! 下面的注释

引用C11,第 §6.5.6/P8 章

当一个整数类型的表达式被添加到指针或从指针中减去时, 结果具有指针操作数的类型。如果指针操作数指向一个元素 一个数组对象,并且数组足够大,结果指向一个元素的偏移量 原始元素使得结果和原始的下标的差异 数组元素等于整数表达式。换句话说,如果表达式P 指向 数组对象的i-th 元素,表达式(P)+N(等效于N+(P))和 (P)-N(其中N 的值为n)分别指向i+n-th 和i−n-th 元素 数组对象,前提是它们存在。 [....]

然后,关于上面提到的未定义行为,

[....] 如果两个指针 操作数和结果指向同一数组对象的元素,或最后一个元素 数组对象的元素,评估不应产生溢出;否则, 行为未定义。如果结果指向数组对象的最后一个元素,它 不得用作被评估的一元 * 运算符的操作数。


话虽如此,printf() 声明也是错误的。您有两个转换说明符,但提供了三个参数。这不是有害,而是无用/无意义。

相关,来自第 §7.21.6.1/P2 章,

[...] 如果格式已用尽而参数仍然存在,则多余的参数将 评估(一如既往),但在其他方面被忽略。 [...]

基于本例,可以直接使用

printf("5th position %d:%s:\n",ds[5].id,ds[5].buffer);

【讨论】:

  • 为了完成我的代码工作,我修改了这一行:iterator = ds + 5。谢谢!!!
  • @RubénPozo 啊,对,让我也纠正一下。
  • @Bathsheba 我可以看到从马里亚纳海沟到珠穆朗玛峰顶部的景色。
  • 我发现在回答显然是基本问题时,仅仅引用标准并不能帮助很多人。大多数人在这个级别的问题也需要简单的英语解释。
  • @Joe,这就是为什么选择答案总是对 SO 有用的原因。 Sourav Ghosh 喜欢使用标准参考,这使他的答案具有参考质量。我倾向于不这样做,主要是因为我本质上是一个不知道标准的江湖骗子。请记住,SO 是一个问答网站,而不是一个旨在帮助个人用户的论坛(尽管必然会退出)。
【解决方案2】:

行为

iterator = ds + (sizeof(dummy_struct) * 5);

is undefined 如果您将指针设置为超过数组的最后一个元素。实际上,您将iterator 设置为数组中比您想象的更多的元素,系数为sizeof(dummy_struct)!不要那样做。

该语言允许您使用符号iterator = ds + 5;。这种惯用的指针算法5 大量sizeof(dummy_struct) 添加到地址iterator。换句话说,编译器会为您进行sizeof 调整。这就是指针算法如此强大的原因之一。

最后注意*(ds + 5)等价于ds[5]。我发现后者在处理数组时更清晰。

【讨论】:

    【解决方案3】:

    似乎您正试图使iterator 指针指向5th 数组的5th 元素。但是这个语句会给你错误的结果:

    iterator = ds + (sizeof(dummy_struct)*5);
    

    sizeof(dummy_struct)*5 的结果将导致结构体 dummy_struct 的所有元素的总大小乘以 5,将添加到 ds 引用的地址并分配给 iterator。因此,iterator 可能指向您的程序不拥有的内存位置。你需要做的:

    iterator = ds + 5;
    

    或者你也可以这样做:

    iterator = &ds[5];
    

    【讨论】:

    • &ds[4] 等价于 ds + 4。还要注意编译器不允许在前一个表达式中取消引用 ds + 4
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-16
    • 1970-01-01
    • 2019-01-07
    • 2023-03-17
    • 2014-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多