我在HSW上看到了这个程序:
int *p;
int i;
p = (int *)malloc(sizeof(int[10]));
for (i=0; i<10; i++)
*(p+i) = 0;
free(p);
我完全不了解循环。
假设内存是字节可寻址的,并且每个整数占用4个字节的内存,并且我们将40个字节的内存分配给从地址p
到0
的指针39
。
现在,根据我的理解,指针p
最初包含值0
,即第一个内存位置的地址。在循环中,向指针添加位移以访问后续整数。
我无法理解如何使用仅39
的位移值访问内存地址up 0 to 9
。我检查并发现指针以4的倍数递增。这是怎么发生的?我猜它是因为整数类型指针,并且每个指针应该增加它的数据类型的大小。这是真的吗?
但是如果我真的想用一个整数指针指向内存位置2怎么办呢。所以,我这样做:p = 2
。然后,当我尝试取消引用此指针时,我是否应该期待分段错误?
答案 0 :(得分:2)
由于您有类型指针,当您对其执行常规操作(加法或减法)时,它会自动调整您的类型的对齐方式。在此处,由于您的计算机sizeof (int)
为4
,因此p + i
会在您的案例中生成地址p + sizeof (int) * i
或p + 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开始的物理位置,如果你是其他人所说的是正确的。