从基础开始,单指针有两个目的:创建数组,并允许函数更改其内容(通过引用传递):
char *a; a = malloc...
要么
void foo (char *c); //means I'm going to modify the parameter in foo. { *c = 'f'; } char a; foo(&a);
双指针可以是2D数组(或数组数组,因为每个“列”或“行”不需要是相同的长度).我个人喜欢在需要传递一维数组时使用它:
void foo (char **c); //means I'm going to modify the elements of an array in foo. { (*c)[0] = 'f'; } char *a; a = malloc... foo(&a);
对我来说,这有助于描述foo正在做什么.但是,没有必要:
void foo (char *c); //am I modifying a char or just passing a char array? { c[0] = 'f'; } char *a; a = malloc... foo(a);
也会工作.
根据this question的第一个答案,如果foo要修改数组的大小,则需要双指针.
人们可以清楚地看到如何需要一个三重指针(以及真正的超级指针).在我的情况下,如果我传递一个指针数组(或数组数组),我会使用它.显然,如果你传入一个改变多维数组大小的函数,那将是必需的.当然,一组数组数组并不常见,但其他情况则是如此.
那么有哪些约定呢?这真的只是一个风格/可读性的问题,而且许多人很难将自己的脑袋缠绕在指针上吗?
解决方法
我们假设你在这里有一个小函数声明:
void fun(int***);
嗯.参数是三维锯齿状数组,或指向二维锯齿状数组的指针,还是指向数组指针的指针(如,函数分配数组并在函数内指定指向int的指针)
让我们来比较一下:
void fun(IntMatrix*);
当然你可以使用int指针来对矩阵进行操作.但那并不是他们的本性.它们在这里作为三重指针实现的事实与用户无关.
应该封装复杂的数据结构.这是面向对象编程的一个明显的想法.即使在C语言中,您也可以在某种程度上应用此原则.将数据结构包装在结构中(或者,在C中非常常见,使用“句柄”,即指向不完整类型的指针 – 这个成语将在后面的答案中解释).
让我们假设您将矩阵实现为双锯齿状的数组.与连续的2D数组相比,它们在迭代时更糟(因为它们不属于单个连续内存块)但允许使用数组表示法进行访问,并且每行可以具有不同的大小.
所以现在的问题是你现在无法改变表示形式,因为指针的使用是硬连接在用户代码上的,现在你已经陷入了劣质的实现.
如果将它封装在结构中,这甚至不会成为问题.
typedef struct Matrix_ { double** data; } Matrix; double get_element(Matrix* m,int i,int j) { return m->data[i][j]; }
只是改变为
typedef struct Matrix_ { int width; double data[]; //C99 flexible array member } Matrix; double get_element(Matrix* m,int j) { return m->data[i*m->width+j]; }
句柄技术的工作原理如下:在头文件中,您声明了一个不完整的结构体以及处理结构指针的所有函数:
// struct declaration with no body. struct Matrix_; // optional: allow people to declare the matrix with Matrix* instead of struct Matrix* typedef struct Matrix_ Matrix; Matrix* create_matrix(int w,int h); void destroy_matrix(Matrix* m); double get_element(Matrix* m,int j); double set_element(Matrix* m,double value,int j);
typedef struct Matrix_ { int width; double data[]; //C99 flexible array member } Matrix; double get_element(Matrix* m,int j) { return m->data[i*m->width+j]; } /* definition of the rest of the functions */
世界其他地方不知道结构Matrix_包含什么,它不知道它的大小.这意味着用户不能直接声明值,而只能使用指向Matrix和create_matrix函数的指针.但是,用户不知道大小的事实意味着用户不依赖它 – 这意味着我们可以随意删除或添加成员结构Matrix_.