目录
前言:
一、字符指针
二、指针数组与数组指针
(一)指针数组
(二)数组指针
三、数组传参与指针传参
(一)数组传参
(二)指针传参
前言:
进阶指针我打算分三篇文章进行讲解,第一篇主要围绕数组与指针进行,第二篇主要围绕函数指针进行,最后一篇会引入面试题讲解。
指针的基本概念:
1、指针就是个变量,用来存放地址,地址唯一标识一块内存空间。
2、指针的大小是固定的4/8个字节(32位/64位)
3、指针是有类型,指针的类型决定的指针+-整数的步长,指针解引用操作的权限。
一、字符指针
字符指针就是指针类型为字符的指针:char*。
可以这样定义:
int main()
{
char ch = 'w';
char* pc = &ch;
*pc = 'w';
return 0;
}
如果是字符串呢?
int main()
{
char* pstr = "hello world.";
printf("%s\n", pstr);
return 0;
}
注意这里指针变量pstr中存放的是字符串中首字符的地址。
一道面试题:
int main()
{
char str1[] = "hello world.";
char str2[] = "hello world.";
const char* str3 = "hello world.";
const char* str4 = "hello world.";
if (str1 == str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if (str3 == str4)
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}
输出结果:
str1 and str2 are not same
str3 and str4 are same
分析:str1与str2为两个数组,而数组名代表首元素地址,所以str1与str2不相同。而str3与str4指向的是同一个字符串常量,当几个指针指向同一个字符串的时候,他们实际会指向同一块内存。
二、指针数组与数组指针
(一)指针数组
指针数组是数组,数组存放的内容是指针,那么很简单定义数组的时候,数组类型定义为XXX*即可,如:
int* arr1[10]; //整型指针的数组
char* arr2[4]; //一级字符指针的数组
char** arr3[5];//二级字符指针的数组
(二)数组指针
数组指针是指针,指针指向的内容为数组。
观察下面的代码,哪个是数组指针?
int* p1[10];
int (*p2)[10];
注:[]操作符的优先级高于*。
分析:p1为指针数组。p2先于*结合,即p2为指针变量,指针变量的类型为int [10]整型数组,所以p2为数组指针。
我们知道数组名arr表示首元素的地址,那么&arr 取出的是不是首元素的地址呢?
其实数组名表示数组首元素的地址有两个例外:
1、sizeof(arr),sizeof计算的是整个数组大小,单位为字节。
2、&arr,此时取出的是整个数组的地址。
我们利用下面的代码进行验证:
int main()
{
int arr[10] = { 0 };
printf("arr = %p\n", arr);
printf("&arr= %p\n", &arr);
printf("arr+1 = %p\n", arr + 1);
printf("&arr+1= %p\n", &arr + 1);
return 0;
}
结果为:
我们发现&arr+1跳过的是整个数组的大小。
数组指针一般用于二维数组中。如:
void print_arr1(int arr[3][5], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
void print_arr2(int(*arr)[5], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };
print_arr1(arr, 3, 5);
//数组名arr,表示首元素的地址
//但是二维数组的首元素是二维数组的第一行
//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
//可以数组指针来接收
print_arr2(arr, 3, 5);
return 0;
}
三、数组传参与指针传参
如何将【数组】或【指针】作为参数传给函数呢?
(一)数组传参
正确设计:
void test1(int arr[])
{}
void test1(int arr[10])
{}
void test1(int* arr)
{}
void test2(int* arr[20])
{}
void test2(int** arr)
{}
void test3(int arr[3][5])
{}
void test3(int arr[][5])
{}
void test3(int (*arr)[5])
{}
int main()
{
int arr1[10] = { 0 };
int* arr2[20] = { 0 };
int arr3[3][5] = { 0 };
test1(arr1);
test2(arr2);
test3(arr3);
}
错误设计:
void test3(int arr[][])//err
{}
void test3(int* arr)//err
{}
void test3(int* arr[5])//err
{}
void test3(int** arr)//err
{}
int main()
{
int arr1[10] = { 0 };
int* arr2[20] = { 0 };
int arr3[3][5] = { 0 };
test1(arr1);
test2(arr2);
test3(arr3);
}
错误分析:
首先要搞清楚函数参数的类型,test3(arr3)中明显传入的是arr3数组的首元素地址,又arr3为二维数组,所以该函数实际传入参数为arr3首行元素的地址,本质是指针。
然后我们看函数定义中设计的参数:
void test3(int arr[][])二维数组可以省略行,但是不能省略列,所以该函数设计错误。
void test3(int* arr)此函数设计参数类型为指针数组,本质是数组,与传入参数不符,所以该函数设计错误。
void test3(int* arr[5])同上。
void test3(int** arr)此函数设计参数类型为二级指针数组,本质是数组,与传入参数不符,所以该函数设计错误。
(二)指针传参
void print(int* p, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d\n", *(p + i));
}
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9 };
int* p = arr;
int sz = sizeof(arr) / sizeof(arr[0]);
//一级指针p,传给函数
print(p, sz);
return 0;
}
当函数的参数部分为一级指针时,该函数能接收什么参数呢?
比如:void test(char* p)
以下供参考:
void test(char* p)
{}
int main()
{
char ch = 'w';
char ptr = &ch;
char arr[] = "abcdef";
test(&ch);
test(ptr);
test(arr);
}
当函数的参数部分为二级指针时,该函数又能接收什么参数呢?比如:
void test1(int** p1)
void test2(char** p2)
以下供参考:
void test1(int** p)
{}
void test2(char** p)
{}
int main()
{
int n = 10;
int* p1 = &n;
int** pp = &p1;
test1(pp);
test1(&p1);
char c = 'b';
char* pc = &c;
char** ppc = &pc;
char* arr[10];
test2(&pc);
test2(ppc);
test2(arr);
return 0;
}
今天的内容就分享到这,接下来博主还会继续跟进进阶指针的更新,关注博主不迷路🔥🔥🔥