增加指向数组的指针

时间:2013-02-26 13:35:05

标签: c arrays pointers

我在HSW上看到了这个程序:

int *p;
int i;

p = (int *)malloc(sizeof(int[10]));
for (i=0; i<10; i++)
    *(p+i) = 0;
free(p);

我完全不了解循环。 假设内存是字节可寻址的,并且每个整数占用4个字节的内存,并且我们将40个字节的内存分配给从地址p0的指针39
现在,根据我的理解,指针p最初包含值0,即第一个内存位置的地址。在循环中,向指针添加位移以访问后续整数。

我无法理解如何使用仅39的位移值访问内存地址up 0 to 9。我检查并发现指针以4的倍数递增。这是怎么发生的?我猜它是因为整数类型指针,并且每个指针应该增加它的数据类型的大小。这是真的吗?

但是如果我真的想用一个整数指针指向内存位置2怎么办呢。所以,我这样做:p = 2。然后,当我尝试取消引用此指针时,我是否应该期待分段错误?

5 个答案:

答案 0 :(得分:2)

由于您有类型指针,当您对其执行常规操作(加法或减法)时,它会自动调整您的类型的对齐方式。在此处,由于您的计算机sizeof (int)4,因此p + i会在您的案例中生成地址p + sizeof (int) * ip + 4*i

你似乎误解了*(p+i) = 0这句话。该陈述等同于p[i] = 0。显然,您的malloc()来电不会返回0,除非它无法实际分配您提出的内存。

然后,我假设您的最后一个问题意味着“如果我将我的malloc-ated地址移动两个字节,会发生什么?”。

答案取决于您接下来要做什么以及系统的字节顺序。例如:

/*
 * Suppose our pointer p is well declared
 * And points towards a zeroed 40 bytes area.
 * (here, I assume sizeof (int) = 4)
 */

int *p1 = (int *)((char *)p + 2);
*p1 = 0x01020304;
printf("p[0] = %x, p[1] = %x.\n", p[0], p[1]);

将输出

  

p [0] = 102,p [1] = 3040000。

在大端系统上,

  

p [0] = 3040000,p [1] = 102

在一个小端系统上。

编辑:要回答您的评论,如果您尝试取消引用随机分配的指针,可能会发生以下情况:

  • 您很幸运:您输入的地址对应于已为您的程序分配的内存区域。因此,它是一个有效的虚拟地址。你不会得到段错误,但如果你修改它,它可能会破坏你的程序的行为(它肯定会......)。
  • 你更幸运:地址无效,你得到一个很好的段错误,阻止你的程序完全搞砸了。

答案 1 :(得分:2)

  

现在,根据我的理解,指针p最初包含值0

不,如果p成功返回,指针0将不会保留值malloc

在声明它时,指针未初始化,并且很可能包含垃圾值。一旦将其分配给malloc返回的指针,指针就会指向分配器视为未占用的动态分配内存区域。

  

我无法理解如何访问内存地址uptil 39   位移值仅为0到9

实际位移值为0, 4, 8, 12 ... 36。因为指针p具有类型,在这种情况下int *,这表示指针算术中应用的偏移量为sizeof(int),在您的情况下为4。换句话说,位移乘数总是基于指针所指向的类型的大小。

  

但是如果我真的想用一个指向内存位置2怎么办?   整数指针。所以,我这样做:p = 2.然后,当我尝试   如果我预计会出现分段错误,请取消引用此指针吗?

确切位置2很可能在您的进程的地址空间中不可用,因为该部分将由操作系统保留,或者将以其他形式受到保护。所以在这个意义上,是的,你会得到一个分段错误。

然而,一般的问题是,在不能被其大小整除的位置访问数据类型会破坏对齐要求。许多架构都坚持在4字节边界上访问整数,在这种情况下,您的代码将触发未对齐的内存访问,这在技术上是未定义的行为。

答案 2 :(得分:2)

  

现在,根据我的理解,指针p最初包含值0

不,它包含10个数组中第一个整数的地址。(假设malloc成功。)

  

在循环中,向指针添加位移以访问后续整数。

不,不。我不确定你的意思,但这不是代码所做的。

  

我检查过并发现指针以4的倍数递增。这是怎么发生的?

指针算法,即在指针上使用+ - ++ - etc运算符,足够聪明,可以知道类型。如果你有一个int指针写p ++,那么存储在p中的地址将增加sizeof(int)个字节。

  

但是如果我真的想用一个整数指针指向内存位置2怎么办呢。所以,我这样做:p = 2.

不,不要那样做,这没有任何意义。它将指针设置为指向内存中的地址0x00000002。


代码说明:

int *p;是指向整数的指针。通过编写*p = something,您可以更改p指向的内容。通过编写p = something,您可以更改p指向的地址

p = (int *)malloc(sizeof(int[10]));是由一个困惑的程序员写的。将malloc的结果强制转换为没有任何意义,您可以在此站点上找到有关该主题的大量信息。

撰写sizeof(int[10])与撰写10*sizeof(int)相同。

*(p+i) = 0;与撰写p[i] = 0;

完全相同

我会修改代码如下:

int *p = malloc(sizeof(int[10]));
if(p == NULL) { /* error handling */ }

for (int i=0; i<10; i++)
{
  p[i] = 0;
}

free(p);

答案 3 :(得分:1)

它被称为指针算术。向n类型的指针添加整数t*,将指针移动n * sizeof(t)个元素。因此,如果sizeof(int)是4个字节:

p + 1 (C) == p + 1 * sizeof(int) == p + 1 * 4 == p + 4

然后索引数组更容易:

*(p+i)是数组p中的第i个整数。

答案 4 :(得分:0)

我不知道“内存位置2”是指你的示例内存地址2,还是你的意思是数组中的第二个值。如果你的意思是第二个值,那就是内存地址1。要获取指向此位置的指针,您可以int *ptr = &p[1];或等效int *ptr = p + 1;,然后您可以使用printf("%d\n", *ptr);打印此值。如果您的意思是内存地址2(您的示例地址),那将是数组中的第3个值,那么您需要p[2]p + 2。请注意,内存地址通常为十六进制,实际上不会从0开始。它类似于0x092ef000, 0x092ef004, 0x092ef008, . . .。所有其他答案都没有理解您正在使用内存地址0 . . . 39作为示例地址。我不认为你真的指的是从地址0x00000000开始的物理位置,如果你是其他人所说的是正确的。