我是一名中级程序员,正在努力学习标准C.我正在努力完成一项课程练习,其中包括使用指针将不同类型的数据类型存储到char类型的数组中。
假设我有一个大的char数组:
static char arr[1000];
正如我的教授解释的那样,我可以认为这是一块本地内存,其中数组中的每个元素都具有一个字节的粒度。这似乎很有用。现在假设我想获取前四个字节/元素并存储一个int:
int a = 100;
int* ptr = (int*)arr;
*ptr = a;
据我所知,第二行创建一个int *指针,然后将其指向数组arr的开头。第三行将a的值写入该位置。因为ptr是一个int类型的指针,因为arr有足够的空间,所以写入四个字节/四个元素的数据,因为sizeof(int)== 4.通过我的调试器仔细观察这个似乎证实了这一点。
到目前为止,这么好。现在让我们说我想扩展这个概念。假设我想按照以下顺序将以下内容存储到我的数组中:
int a = 100;
int b = 200;
char* str = “My dog has fleas”
int c = 300;
逻辑上看起来像这样:
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
--------------------------------------------------------------------------------------
[ 100 ] [ 200 ] M y d o g h a s f l e a s \0 [ 300 ]
我需要能够以这种方式将数据存储到数组中,然后,事先知道数组结构,就能够读取数组。以下是我的代码&输出,很抱歉提前长。它编译但不起作用。用我的调试器仔细检查它一直很混乱;我无法分辨我偏离轨道的位置(以及频率)。如果有人有任何见解或建议,我将非常感激。
int main(){
static char arr[1000];
int a = 100;
int b = 200;
char* str = "My dog has fleas";
int c = 300;
// Create pointers to load data:
int* ptrA = arr; // points to start of array
int* ptrB = ptrA + sizeof(int); // points 4 bytes into array
char* ptrStr = ptrB + sizeof(int); // points 8 bytes into array
int* ptrC = ptrStr + sizeof("My dog has fleas"); // points to after the string
// (I don't know how to use sizeof() to measure the actual length of the string
// Load data into my array
*ptrA = a; // Assign int 100 into the array?
*ptrB = b; // Assign int 200 into the array?
*ptrStr = memcpy(ptrStr, str, sizeof("My dog has fleas")); // Write "My dog has fleas" into the array?
*ptrC = c; // Assign int 300 into the array?
// Knowing the array's structure, walk it and print results:
char* walkIt = arr;
int counter = 0;
while (counter < 30) {
if (counter == 0) {
// we are pointing at what should be the first int
int* tmpPtr1 = (int*)walkIt;
printf("%d ", *tmpPtr1);
}
else if (counter == 4) {
// we are pointing at what should be the second int
int* tmpPtr2 = (int*)walkIt;
printf("%d ", *tmpPtr2);
}
else if (counter == 8) {
// we are pointing at what should be the string
printf("%s ", walkIt);
}
else if (counter == 25) {
// we are pointing at what should be the third int
int* tmpPtr3 = (int*)walkIt;
printf("%d ", *tmpPtr3);
}
walkIt++; // Continue walking the array
counter++; // Don't walk too far
}
return 0;
}
输出是这样的:
100 0 0
答案 0 :(得分:2)
首先,你的教授是错误的,但事实上,事情可能就是这样,取消引用通过指向不同类型的指针获得的指针违反strict aliasing规则,这是编译器假设两个不同类型的指针不能引用相同的内存,从而允许对这些指针进行优化。
回到你的代码,问题是如何计算基址的偏移量,例如:
int* ptrB = ptrA + sizeof(int);
现在,ptrA
为int*
,向指针添加整数偏移会隐式地将偏移量乘以指向的元素的大小。这意味着您不能添加sizeof(int)
个字节但sizeof(int)*sizeof(int)
个字节。
要强制添加特定数量的字节,必须将指针强制转换为char*
,以便添加sizeof(int)
个字节只会添加sizeof(int)*sizeof(char) == sizeof(int)*1
个字节。
int* ptrB = (char*)ptrA + sizeof(int); // points 4 bytes into array
请注意,此代码不安全并且必然会失败,使用union
将是更好的解决方案。