简单的指针算术问题

Posted

技术标签:

【中文标题】简单的指针算术问题【英文标题】:Simple pointer arithmetic problems 【发布时间】:2012-04-16 00:55:09 【问题描述】:

问题一:

我正在阅读 K&R 的书,对某事感到有些困惑。 我对一些简单的指针算术有点困惑。 如果我说

char (*a)[10];

我知道我刚刚声明了一个指向 10 个字符的数组的指针。 首先,因为我没有 malloc,所以这仍然保留在堆栈中,对吗?那么堆栈中有这个指针指向大小为 10 的 char 数组的开头对吗?

现在,如果我想访问数组中的第二个元素,我还会这样做吗? *(a+2*sizeof(char))?还是在这种情况下不起作用?

问题 2:

如果我有

int* a = malloc(10*sizeof(int));

如果我想从整数数组中获取第二个 byte, 我会这样做:

*((char*)((char*)a+2))

这对吗?

谢谢。

【问题讨论】:

你可能想把你的问题分开。这样你就可以得到每个人的最佳答案 char (*a)[10]; 定义了指向数组的指针,而不是数组。而且它是未初始化的,所以取消引用它是UB。对它做指针运算也是UB,因为指针运算只在数组中定义。 【参考方案1】:

第一件事

In C/C++, array index starts from 0 instead of 1。因此,如果要访问第二个元素,请使用索引 1,而不是 2!

回答 1

char (*a)[10];

是的,这是一个指向大小为 10 的数组的指针。指针本身在堆栈上。但它没有指向任何有效的数组,对于这一行,这意味着它是未初始化的。

要初始化你的指针,

char b[2][10] = "123456789", "abcdefghi";
// initialize pointer "a"
char (*a)[10] = b;

要访问“第二个”元素,在本例中为“2”,请使用,

char (*a)[10] = b;
// access the element at 1st row, 2nd column
printf("%c\n", a[0][1]);

答案 2

您想访问第二个字节。但是,元素索引从 0 开始而不是 1,因此您应该使用“+1”而不是“+2”作为第 2 个字节!

*((char*)a+1);

【讨论】:

你在答案的最后部分有一个额外的演员 - *((char*)a+1); 也可以。【参考方案2】:

当你声明指针时,它还没有指向任何东西。如果您希望它在堆栈上,则需要声明一个大小为 10 的字符数组并将其地址分配给 (*a)[10]。至于访问第二个元素,大多数编译器可以为下一个元素执行*(a+1)(因此对于4字节的int,*(a + 1)是第二个元素,*(a + 4)是第4个元素(不是第 4 个字节)。

char (*a)[10];
char arrayTest[10];
a=&arrayTest;

你的第二个问题,得到第二个字节将是*a,然后简单地做一个右移:

char Test= ((*a)&0x7FFF)>>8;

【讨论】:

您还想屏蔽转换,因为将整数分配给目标类型不能保存值的有符号整数类型会调用未定义的行为。 你能举个例子吗?他将整数的第二个字节分配给一个字符。 是的,但是如果你将一个整数右移 8 位,结果仍有可能大于char 类型的范围,并且根据 C 标准,如果你分配一个大于有符号整数类型范围的值,行为未定义,因此您需要屏蔽结果以确保它适合 char 类型,或者,使用 unsigned char 代替(这可能是更多合适的选择)。 许多实现可能允许将大整数分配给char 类型,但由于标准不保证这种情况下的任何特定行为,因此应该避免。【参考方案3】:

问题一:

首先,因为我没有malloc,所以这仍然全部保存在堆栈中吧?

指针在堆栈上声明,但它还没有指向任何东西。您需要执行以下操作:

char (*a)[10];
char array[10];
a = &array;

否则a 不指向任何东西,并且尝试访问它会导致问题。

现在,如果我想访问数组中的第二个元素,我还会这样做*(a+2*sizeof(char))

您不需要说sizeof(char),因为编译器会使用您正在使用的指针或数组的类型为您计算加法的大小。此外,如果您想要第二个元素,则需要添加 1 而不是 2(因为数组/指针索引从零开始)。

如果您想要指向数组的第二个元素,您可以使用(*a)+1(*a)[1]

如果您的指针指向多个数组,并且您想要第二个数组,那么*(a+1)a[1] 就是您想要的。


问题2:

(下次最好多开多个问题:)

如果我想从整数数组中获取第二个字节,我会这样做:*((char*)((char*)a+2))?

首先,重要的是要意识到,当你说:

int* a = malloc(10*sizeof(int));

你有一个指向一块内存的指针,它有足够的空间容纳 10 个整数——这不是一个数组。如果这令人困惑,请参阅C-FAQ on pointers and arrays。

现在,如果你想要 a 指向的内存块中的第二个字节,你可以说:

char second_byte = *((char*)a+1);

因为强制转换的优先级高于加法,所以在执行加法时a 被视为char*。但是,为了尽量减少阅读代码时产生误解的机会,我可能会这样写:

char second_byte = *(((char*)a)+1);

或更好:

char second_byte = ((char*)a)[1];

相反。请注意,原始示例中的额外演员表是不必要的。

【讨论】:

以上是关于简单的指针算术问题的主要内容,如果未能解决你的问题,请参考以下文章

结构上的指针算术

未检测到越界指针算术?

32位或64位系统中的指针算术长短

指向 char 算术的 C++ 指针

具有数据结构的双指针的算术

警告:算术中使用的“void *”类型指针