c语言二级指针技巧(深入理解二级指针用作函数参数)
c语言二级指针技巧(深入理解二级指针用作函数参数)https://diveintosystems.org/book/C2-C_depth/arrays.html#include <stdio.h> #include <malloc.h> int** demo(int row int col) { // the 2D array variable is declared to be `int **` (a pointer to an int *) // a dynamically allocated array of dynamically allocated int arrays // (a pointer to pointers to ints) int **two_d_array; int i; // allocate an array of N po
我们知道,函数传址可以产生副作用,如一级指针做函数参数可以对一个普通变量产生副作用:
int x = 0;
void demo(&x);#include <stdio.h>
#include <malloc.h>
void demo(int* p);
main()
{
int x = 0;
demo(&x);
printf("%d\n" x);//11
getchar();
}
void demo(int* p)
{
*p = 11; // 操作p的目标对象,可以产生副作用
p = (int*)malloc(sizeof(int));// 操作自身,作为本函数的临时变量,不影响主调函数
*p = 22;
}
printf("%d\n" x);
如果需要对一个一级指针产生产生副作用,需要将一级指针的地址传递给被调函数,所以,被调函数需要一个二级指针用做函数参数:
#include <stdio.h>
#include <malloc.h>
void demo(int** p);
main()
{
int x = 0;
int* p = &x;
*p = 11;
demo(&p);
printf("%d %d\n" x *p);//11 22
getchar();
}
void demo(int** p)
{
*p = (int*)malloc(sizeof(int));// 操作p的目标对象,可以产生副作用
**p = 22;
p = NULL; // 操作自身,作为本函数的临时变量,不影响主调函数
}
我们知道,单链表的节点通常存储在堆上,所以节点通常用指针指向,对于不带头节点的单链表,相关操作时可能会修改到头节点(一个一级指针),所以相关操作的一些函数就需要一个二级指针做函数参数来产生副作用:
#include <stdio.h>
#include <malloc.h>
struct Node{
int data;
struct Node *next;
};
void listInsert(struct Node **head int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
if(*head!=NULL)
newNode->next = *head;
*head = newNode;// 头节点为实节点
}
void listPrint(struct Node *head)
{
while(head!=NULL)
{
printf("%d " head->data);
head = head->next;
}
printf("\n");
}
void listDel(struct Node *head); // 略
int main()
{
struct Node *head = NULL;
for(int i=1;i<11;i )
listInsert(&head i);
listPrint(head);
getchar();
}
我们知道,指针数组是指一个元素是一级指针的一维数组,数组名做右值时在一定的上下文中(数组名不是操作符&、sizeof的操作数时)是一个指向数组首元素的指针,而指针数组的元素又是指针,所以指针数组名在一定的上下文中等同于一个二级指针。
#include <stdio.h>
#include <malloc.h>
void test(int **p)
{
// p,p是一个指针,其偏移的地址或字节数以目标类型(这里是int*)的内存大小为步长
// p解引用:*p做左值产生副作用
* p = (int*)malloc(sizeof(int));
**p = 11;
}
main()
{
int* arr[7] = {0}; // 静态数组
int** p = arr;
test(arr);
printf("%d\n" *arr[1]); // 11
printf("%d\n" arr[1][0]); // 11
getchar();
}
如何理解 p,关键在于理解p的目标类型是int*。
p[i]是*(p i)的语法糖,其自身类型是int*,目标类型是int。
以上数组arr是静态分配的静态数组,也可以动态分配堆内存,形成一个动态指针数组,其元素再在堆内存上动态分配一维数组,便可以在逻辑上形成一个动态二维数组:
#include <stdio.h>
#include <malloc.h>
int** demo(int row int col)
{
// the 2D array variable is declared to be `int **` (a pointer to an int *)
// a dynamically allocated array of dynamically allocated int arrays
// (a pointer to pointers to ints)
int **two_d_array;
int i;
// allocate an array of N pointers to ints
// malloc returns the address of this array (a pointer to (int *)'s)
two_d_array = (int**)malloc(sizeof(int *) * row);
// for each row malloc space for its column elements and add it to
// the array of arrays
for (i = 0; i < row; i ) {
// malloc space for row i's M column elements
two_d_array[i] = (int*)malloc(sizeof(int) * col);
}
return two_d_array;
}
/*
* initialize a 2D array
* arr: the array
* rows: number of rows
* cols: number of columns
*/
void init2D(int **arr int rows int cols) {
int i j;
for (i = 0; i < rows; i ) {
for (j = 0; j < cols; j ) {
arr[i][j] = (i 1)*(j 1);
}
}
}
void print(int **arr int rows int cols) {
int i j;
for (i = 0; i < rows; i ) {
for (j = 0; j < cols; j ) {
printf("%d " arr[i][j]);
}
printf("\n");
}
}
int main() {
int row col;
row = 3;
col = 4;
int **two_d_array = demo(row col);
init2D(two_d_array row col);
print(two_d_array row col);
int *arr[3];
for(row=0;row<3;row )
arr[row] = (int*)malloc(sizeof(int)*4);
init2D(arr 3 4);
print(arr 3 4);
getchar();
}
ref
https://diveintosystems.org/book/C2-C_depth/arrays.html