指针是检验学者对C语言掌握好与坏的重要标准之一,在指针初阶中,我们以及详细介绍了以下内容:
接下来,我们将继续探讨指针的高级主题。
在指针的类型中我们知道有一种指针类型位字符指针 char*
一般用法:
int main()
{
char ch = 'w';
char* pc = &ch;
*pc = 'a';
return 0;
}
还有一种使用方法:
int main()
{
const char* pstr = "hello world";
printf("%s\n", pstr);
return 0;
题目:
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 atr4 are not same\n");
return 0;
}
**这里str3和str4指向的是同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,实际上他们会指向同一块内存。
但是用相同的常量字符串去初始化不同的数组时会开辟不同的内存块。
所以str1和str2不同;str3和str4相同。
在指针初阶中我们已经介绍了指针数组,指针数组是一个存放指针的数组。
在这里我们在简单复习一下,下面数组是什么意思?
int* p1[10]; //整型指针的数组
char *arr2[4];//一维字符指针的数组
char** arr3[5]; //二级字符指针的数组
首先说明数组指针是指针。
我们已经熟悉:
整型指针:int * pint; 能够指向整型数据的指针。
浮点数指针:float * pf; 能够指向浮点型数据的指针。
那么数组指针应该是:能过指向数组的指针。
下面代码那个是数组指针?
int* p1[10];
int(*p2)[10];
解读:
int* p1[10];
//解释:从p1开始,由于[]的优先级高于*,p1先后[]结合,所以p1是一个数组。
// 然后在与*结合,说明数组中的元素是指针类型;在和int结合说明指针所指向的内容的类型是指针类型
// 所以p1是由一个返回整型数据的指针所组成的数组(p1为指针数组)
int(*p2)[10];
//解释:由于()的优先级高于[]。所以从p2开始,先和*结合说明p2是一个指针。
// 在和[]结合,说明指针所指向的内容是一个数组;在和int结合,说明数组中的每一个元素是整型类型
// 所以p2是指向一个由整型数据组成的数组的指针。(p2是一个数组指针)
对于下面的数组:
int arr[10];
arr和&arr分别是什啥?
我们知道arr是数组名,数组名表示首元素地址。那&arr数组名到底是什么呢?
我们先来看下面几段代码:
代码一:
int main()
{
int arr[10] = { 0 };
printf("%p\n", arr);
printf("%p\n", &arr);
return 0;
}
运行结果:
在上面这段代码中,数组名和&数组名打印的地址是一样的。
难道两个真是一样的吗?
我们再来看下面这段代码:
代码一:
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和&arr值是一样的,但意义不同。
实际上:&arr 表示的是数组的地址,而不是数组首元素的地址。
本例中 &arr 的类型是:int (*)[10],是一种数组指针类型。
数组的指针+1,跳过整个数组的大小,所以 &arr 相对于 arr 的差值为40。
介绍完数组指针,那数组指针如何使用呢?
既然数组指针指向的是数组,那数组指针中存放的应该就是数组的地址。
一个数组指针的使用:
//void print_arr(int arr[3][5], int row, int col)
void print_arr(int (*arr)[5], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int 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},{11,12,13} };
print_arr(arr, 3, 5);
//数组名arr,表示首元素地址
//但二维数组的首元素是二维数组的第一行
//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址,可以使用一维数组来接受
return 0;
}
学习了数组和数组指针,接下来我们来看看下面这些代码的意思:
int arr[5];
//解读:arr先和[]结合,说明arr是一个数组;在和int结合,说明数组中的元素是int类型。
// 所以arr是由整型数据组成的数组
int *parr1[10];
//解读:parr1先和[]结合,说明pass1是一个数组;在和*结合,说明数组的元素是指针类型;最后和int结合,说明指针指向的内容的类型是整型。
// 所以pass1是有一个返回整型数据的指针所组成的数组。
int (*parr2)[10];
//解读:parr2先和*结合,说明parr2是一个指针;在和[]结合,说明指针所指向的内容是一个数组;最后和int结合,说明数组中的元素是整型类型。
// 所以parr2是一个指向由整型数据组成的数组的指针。
int (*parr3[10])[5];
//解读:parrr3先和先和[]结合,说明parr3是一个数组;在和*结合,说明数组的元素是指针类型;在和[]结合,说明指针指向的是一个数组;最后和int结合说明,数组中的元素类型是整型。
// 所以parr3是一个由指向整型数组的指针组成的数组。
其他各种复杂数据类型和上面一样,根据操作符优先级一步步分析即可得到答案!!
在写代码时,难免要把数组或指针传个函数,那么函数的参数该如何设计呢?
void test(int arr[])//ok 形参写成一维数组形式,可以不用指定大小
{}
void test(int arr[10])//ok
{}
void test(int *arr)//ok
{}
void test2(int *arr2[10])//ok
{}
void test2(int** arr)//ok arr2的地址时,传的是首元素地址。而首元素的类型为int *也是一个地址。
{} //所以arr2传的是一个二级指针
int main()
{
int arr[10] = { 0 };
int* arr2[10] = { 0 };
test(arr);
test2(arr2);
return 0;
}
//参数为二维数组时,形参部分,行可以省略,列不行
void test(int arr[3][5])//ok
{}
void test(int arr[][])//error
{}
void test(int arr[][5])//ok
{}
//二维数组传参,参数为指针时,指针为数组指针,类型为int (*)[5]
void test(int *arr)//error
{}
void test(int *arr[5])//error
{}
void test(int (*arr)[5])//ok
{}
int main()
{
int arr[3][5] = { 0 };
test(arr);
return 0;
}
void print(int* p, int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%d ", *(p + i));
}
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = arr;
int sz = sizeof(arr) / sizeof(arr[0]);
print(p, sz);//一级指针p,传给函数
return 0;
}
void tesy(char **p)
{}
int main()
{
char n = 10;
char* p = &n;
char** pp = &p;
test(pp);
test(&p);
return 0;
}
本篇文章到此就结束了。创作不易,如果对你有帮助记得点赞加收藏哦!感谢您的支持!!