在我最近回来的一个测试中,它有一个问题,“假设这个代码编译,它会做什么?”
代码:
int *ptr
ptr = (int *) malloc( 25 * sizeof(int)); //100 bytes
*ptr = 'x';
*(ptr + 1) = 'x';
.... //go through all the values from 1 to 99 as well
*(ptr +99) = 'x';
我编写了代码并运行它,当用printf(%d, *x)
打印时,结果为120,即x的ascii值。我知道int必须被设置为x,并且当打印为asc时打印ascii值,但是当涉及到malloc的实际效果时,我感到难过,以及所有{ {1}}确实如此。
答案 0 :(得分:2)
在C中,数组和指针非常相似,为简单起见,在这种情况下,将它们视为相同是很方便的。所以,您可以将malloc
视为动态分配25个整数的数组(例如,动态地说int ptr[25]
),或者您可以将其视为阻塞内存中的25个连续整数地址并将它们标记为有效。这样,ptr == &ptr[0]
。解除引用运算符*
意味着“更改存储在此地址的值”,它基本上“撤消”&运营商。所以,*ptr == *(&ptr[0]) == ptr[0]
。此命令只是将ptr [0]设置为等于'x',其ASCII值为120(并将打印为ASCII值,因为该数组的类型为'int'而不是'char'类型)。其余的任务也是这样做的。根据您的编译器和操作系统,ptr + 24以上的任何内容都可能会出现分段错误或无效写入,因为您只分配了25个整数,因此(ptr + 99)不应该是可写地址。如果您只分配了25个插槽,则无法编辑ptr[99]
。
答案 1 :(得分:1)
malloc()
的实际效果,使语句*ptr = 'x';
和子句访问实际上有效。
如果没有内存分配,尝试取消引用指针将调用undefined behavior。
那就是说,
malloc()
是否成功。(ptr + 1)
这样的表达式指向下一个整数的内存位置,而不是内存的下一个字节。因此,表达式n > 24
的RHS的任何(ptr + <n>)
都将调用UB。25 * sizeof(int)
== 100 bytes
的假设是非常具体的实现。如果sizeof(int)
小于4个字节,您最终将在指针算术中访问超出范围的内存(即使您将指针别名为char*
,也可以考虑)。答案 2 :(得分:1)
当涉及malloc的实际效果
时,我感到难过
malloc
调用为您的数组分配空间。当您最初声明ptr
时,它未初始化为指向有效的内存位置:
+---+
ptr: | | ----> ???
+---+
此时尝试读取或写入ptr
将导致未定义的行为;您的代码可能会彻底崩溃,或者可能以某种方式损坏存储,或者出现以便在没有任何问题的情况下运行。
malloc
调用从堆(a.k.a。,动态内存池)中分配空间,并将该空间的第一个元素的地址分配给ptr
:
+---+
ptr: | | ---+
+---+ |
... |
+------+
|
V
+---+
| | ptr[0]
+---+
| | ptr[1]
+---+
...
请注意,自{1989}标准以来,(int *)
电话上的malloc
投射是没有必要的,实际上被认为是不好的做法(根据C89,它可能掩盖了一个错误)。 IMO,写malloc
电话的最佳方式是
T *p = malloc( N * sizeof *p );
其中T
是任何类型,N
是您要分配的T
类型的元素数。由于表达式 *p
的类型为T
,因此sizeof *p
等同于sizeof (T)
。
以及所有*(ptr + i)实际上做了什么。
*(ptr + i)
相当于ptr[i]
,所以
*ptr = 'x';
*(ptr + 1) = 'x';
相当于写作
ptr[0] = 'x';
ptr[1] = 'x';
请注意
*(ptr +99) = 'x';
超出了您已分配的阵列的范围;你只留出足够的空间用于25个整数。同样,此操作(以及*(ptr + i) = 'x';
大于24的任何操作i
)将导致未定义的行为,并且您的代码可能会崩溃,损坏数据或其他方式。
指针算法将指向的类型考虑在内; ptr + 1
生成下一个整数对象的地址,位于ptr
之后的地址。因此,如果ptr
为0x8000
且sizeof (int)
为4,则ptr + 1
会产生0x8004
,不会 0x8001
。
答案 3 :(得分:0)
Oups,C指针算术基于定义 *(ptr + i)
ptr[i]
。
这意味着当你为25个整数分配空间时,超过第24个元素的所有访问都将调用未定义的行为 - 你实际上试图访问一个你不知道它代表什么的内存。
但是,如果使用指向char(或unsigned char)的指针,则允许访问字节级别的任何对象。所以假设你的编译器sizeof(int)是4,这很好:
int *iptr;
char *cptr;
iptr = malloc( 25 * sizeof(int)); //100 bytes since we know that sizeof(int) is 4
cptr = (char *) iptr; // cast of pointer to any to pointer to char is valid
for(int i=0; i<25*sizeof(int); i++) cptr[i] = 'x'; // store chars 'x'
for(int i=0; i<25; i++) {
printf(" %x", (unsigned int) iptr[i]); // print the resulting ints in hexa
}
printf("\n");
假设您使用字符的ASCII表示(非常常见),您应该得到25个值,所有等于0x78787878
,因为0x78是&#39; x&#39;的ASCII码。但是这部分是未指定的标准,只是实现定义。