使用char数组在标准C

时间:2017-02-08 19:22:02

标签: c arrays memory-management casting stack

我是一名中级程序员,正在努力学习标准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    

1 个答案:

答案 0 :(得分:2)

首先,你的教授是错误的,但事实上,事情可能就是这样,取消引用通过指向不同类型的指针获得的指针违反strict aliasing规则,这是编译器假设两个不同类型的指针不能引用相同的内存,从而允许对这些指针进行优化。

回到你的代码,问题是如何计算基址的偏移量,例如:

int* ptrB = ptrA + sizeof(int); 

现在,ptrAint*,向指针添加整数偏移会隐式地将偏移量乘以指向的元素的大小。这意味着您不能添加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将是更好的解决方案。