我有一个打印字符数组内容的函数:
#include <stdio.h>
void print_array(char * array, int n) {
char* start;
for(start = array; start - array < n && printf("%d\n", *start); start++);
}
int main() {
char array[5] = {'a', 'b', 'c', 'd', 'e' };
print_array(array, 5);
return 0;
}
这很适合打印:
97
98
99
100
101
如果我将功能改为:
,问题就开始了void print_array(int * array, int n) {
int* start;
for(start = array; start - array < n && printf("%d\n", *start); start++);
}
然后调用这个函数:
print_array((int*)array, 5);
这会打印垃圾。
1684234849
101
1973473280
8388443
80884992
我在编译时打开了-Wall
并且没有发出任何警告。当我对指针进行类型转换时,为什么我会得到垃圾?
答案 0 :(得分:6)
从int*
到const char*
的转换定义明确。
如果底层数据是int[]
数组,则反之亦然,但是您无法将const char*
指针所指向的数组中的任意点转换为int*
:您可能不符合对齐要求。
因此,在您的情况下,行为是 undefined ,因为您开始使用char
数组。
答案 1 :(得分:2)
正如其他人所指出的那样,你的第二个实现是 undefined 。
正如其他人所说,由于你将 array 的地址从(char *)转换为(int *),编译器会假设你知道你在做什么并且不会抛出一个警告。尝试编译而不使用强制转换来查看您的警告。
现在,为了给你一个特定于体系结构的例子(注意这个例子仍然是 undefined ),请考虑这个:
假设机器架构使用1个字节表示char,4个字节表示int ...
在您的代码中:
char array[5] = {'a', 'b', 'c', 'd', 'e' };
您分配了一个包含5个字符的数组。它们在内存中可能看起来像这样:
0x61 0x62 0x63 0x64 0x65
然后你打电话
print_array(array, 5);
在此用法和上下文中, array 实际上是指向&amp; array [0] 的隐式指针,它是(char *)并指向0x61。
现在在函数调用中,您将数组转换为(int *)。你拥有的是一个由5个元素组成的数组,每个元素宽1个字节,现在被解释(注意:未转换)为(仍然)5个元素的数组,每个元素... 4个字节宽!这可能在内存中看起来像这样:
0x61626364 0x65?????? 0x???????? 0x???????? 0x????????
您的(int *)实现中只需要定义5个字节所需的20个字节。
根据机器的字节顺序,您的第一个int可以解释为
您已经注意到打印时其他4个元素是垃圾,因为我们不知道内存的内容。
另请注意,您在第二个&#34; int&#34;上溢出了char [5]数组。元件。
同样,此示例依赖于体系结构,未定义。你可能在另一个架构上有完全不同的行为。
编辑: 它看起来像是偶然的,你的第二个&#34; int&#34;是
0x65000000
并以小端解释:101就像你在输出中看到的一样。
但这是运气。它可能是任何垃圾。