使用带指针的数组注释

我目前无法理解以下场景:我有一个多维数组的字符串,我想通过仅使用指针来解决它,但我总是在指针上使用数组注释时出现分段错误。 这只是一个示例代码我想在pthread中使用3D数组,所以我想通过结构作为指针传递它,但它只是不起作用,我想知道为什么? 我认为指针和数组在function上是等价的? 以下是示例代码:

#include  void func(unsigned char ***ptr); int main() { // Image of dimension 10 times 10 unsigned char image[10][10][3]; unsigned char ***ptr = image; memcpy(image[0][0], "\120\200\12", 3); // This works as expected printf("Test: %s", image[0][0]); func(image); return 0; } void func(unsigned char ***ptr) { // But here I get a Segmentation Fault but why?? printf("Ptr: %s", ptr[0][0]); } 

在此先感谢您的帮助 :)

我想也许strdup混淆这个问题。 指针和数组并不总是等价的。 让我试着演示一下。 我总是避免使用实际的多维数组,所以我可能会在这里犯一个错误,但是:

 int main() { char d3Array[10][10][4]; //creates a 400-byte contiguous memory area char ***d3Pointer; //a pointer to a pointer to a pointer to a char. int i,j; d3Pointer = malloc(sizeof(char**) * 10); for (i = 0; i < 10; ++i) { d3Pointer[i] = malloc(sizeof(char*) * 10); for (j = 0; j < 4; ++j) { d3Pointer[i][j] = malloc(sizeof(char) * 4); } } //this d3Pointer[2][3][1] = 'a'; //is equivalent to this char **d2Pointer = d3Pointer[2]; char *d1Pointer = d2Pointer[3]; d1Pointer[1] = 'a'; d3Array[2][3][1] = 'a'; //is equivalent to ((char *)d3Array)[(2 * 10 * 4) + (3 * 4) + (1)] = 'a'; } 

通常,我使用分层方法。 如果我想要连续的记忆,我自己处理数学......就像这样:

  char *psuedo3dArray = malloc(sizeof(char) * 10 * 10 * 4); psuedo3dArray[(2 * 10 * 4) + (3 * 4) + (1)] = 'a'; 

更好的是,我使用像uthash这样的集合库。

请注意,正确封装数据会使实际代码非常容易阅读:

 typedef unsigned char byte_t; typedef struct { byte_t r; byte_t g; byte_t b; }pixel_t; typedef struct { int width; int height; pixel_t * pixelArray; }screen_t; pixel_t *getxyPixel(screen_t *pScreen, int x, int y) { return pScreen->pixelArray + (y*pScreen->width) + x; } int main() { screen_t myScreen; myScreen.width = 1024; myScreen.height = 768; myScreen.pixelArray = (pixel_t*)malloc(sizeof(pixel_t) * myScreen.height * myScreen.width); getxyPixel(&myScreen, 150, 120)->r = 255; } 

在C中,您应该一次为您的2D数组分配一行空间。 您对test的定义声明了一个10 x 10的char指针数组,因此您不需要为它调用malloc。 但是要存储字符串,您需要为字符串分配空间。 你对strcpy的调用会崩溃。 请改用strdup。 编写代码的一种方法如下。

  char ***test = NULL; char *ptr = NULL; test = malloc(10 * sizeof(char **)); for (int i = 0; i < 10; i++) { test[i] = malloc(10 * sizeof(char *)); } test[0][0] = strdup("abc"); ptr = test[0][0]; printf("%s\n", ptr); test[4][5] = strdup("efg"); ptr = test[4][5]; printf("%s\n", ptr); 

或者,如果你想保持10×10的定义,你可以这样编码:

  char *test[10][10]; char *ptr = NULL; test[0][0] = strdup("abc"); ptr = test[0][0]; printf("%s\n", ptr); test[4][5] = strdup("efg"); ptr = test[4][5]; printf("%s\n", ptr); 

你的问题是, char[10][10][3]char*** 非常不同 :第一个是数组数组,后者是指向指针的指针。 产生混淆是因为两者都可以用相同的语法解除引用。 所以,这里有一点解释:

  1. 语法a[b]只是*(a + b)的简写 :首先执行指针运算,然后取消引用结果指针。

    但是,当a是数组而不是指针时,你怎么能用a[b] ? 好吧,因为……

  2. 数组衰减成指向第一个元素的指针 :如果你有一个声明为int array[10] array + 3 ,说array + 3导致array衰减为int*类型的指针。

    但是,这有助于评估a[b] ? 好吧,因为……

  3. 指针算法考虑目标的大小 :表达式array + 3触发沿(size_t)array + 3*sizeof(*array) 。 在我们的例子中,由数组指针衰减产生的指针指向一个int ,其大小为4个字节。 因此,指针增加3*4字节。 结果是一个指向数组中第四个int的指针,前三个元素被指针算术跳过。

    请注意,这适用于任何元素类型的数组。 数组可以包含字节,整数,浮点数,结构或其他数组。 指针算术是相同的。

    但是,这对多维数组有何帮助? 好吧,因为……

  4. 多维数组只是一维数组,恰好包含数组作为元素 :使用char image[256][512];声明数组时char image[256][512]; 你声明一个256元素的一维数组。 这256个元素都是512个字符的数组。 由于sizeof(char) == 1 ,外部数组的元素大小为512*sizeof(char) = 512 ,并且由于我们有256这样的数组,因此image的总大小为256*512 。 现在,我可以声明一个带有char animation[24][256][512];的3D数组char animation[24][256][512];


所以,回到你使用的例子

 char image[10][10][3] 

当你说image[1][2][1]是这样的时候会发生什么:表达式相当于这个:

 *(*(*(image + 1) + 2) + 3) 
  1. char[10][10][3]类型的image衰变为指向其第一个元素的指针,该元素的类型为char(*)[10][3]该元素的大小为10*3*1 = 30字节。

  2. image + 1 :执行指针运算以将1添加到结果指针,该指针将其递增30个字节。

  3. *(image + 1) :指针被解除引用,我们现在直接讨论元素,它是char[10][3]

  4. 该数组再次衰减为指向其第一个元素的指针,该元素的类型为char(*)[3] 。 元素的大小为3*1 = 3此指针指向内存中与步骤2产生的指针相同的字节。唯一的区别是,它具有不同的类型!

  5. *(image + 1) + 2 :执行指针运算以将2添加到结果指针,使其递增2*3 = 6个字节。 与步骤2中的增量一起,我们现在总共有36个字节的偏移量。

  6. *(*(image + 1) + 2) :指针被解除引用,我们现在直接讨论元素,它是char[3]类型。

  7. 该数组再次衰减为指向其第一个元素的指针,该元素的类型为char* 。 元素的大小现在只是一个字节。 同样,该指针具有与步骤5得到的指针相同的值,但是具有不同的类型。

  8. *(*(image + 1) + 2) + 1 :再次指针运算,在总偏移量上增加1*1 = 1个字节,增加到37个字节。

  9. *(*(*(image + 1) + 2) + 1) :指针最后一次被解引用,我们现在正在讨论37个字节偏移的charimage


那么, char***的区别是什么? 当你取消引用char*** ,你不会得到任何数组指针衰减 。 当您尝试使用声明为的变量计算表达式pointers[1][2][1]

 char*** pointers; 

表达式再次等同于:

 *(*(*(pointers + 1) + 2) + 3) 
  1. pointers是指针,因此不会发生衰减。 它的类型是char*** ,它指向char**类型的值,它的大小可能是8个字节(假设是64位系统)。

  2. pointers + 1 :执行指针运算以将1添加到结果指针,使其递增1*8 = 8个字节。

  3. *(pointers + 1) :指针被解除引用,我们现在讨论的是在指针指向8字节偏移量的内存中找到的指针值。

  4. 进一步的步骤取决于实际发生在pointers[1]实际情况。 这些步骤不涉及任何数组指针衰减,因此从内存加载指针。


你看, char[10][10][3]char***之间的区别是深刻的。 在第一种情况下,数组指针衰减将进程转换为纯偏移计算为多维数组。 在后一种情况下,我们在访问元素时重复从内存加载指针,我们所有的都是一维指针数组。 这完全取决于指针的类型!