扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
本文重点讲指针的进阶前半部分,主要介绍了指针数组和数组指针。
成都创新互联是一家专注于成都做网站、网站制作与策划设计,调兵山网站建设哪家好?成都创新互联做网站,专注于网站建设十余年,网设计领域的专业建站公司;建站业务涵盖:调兵山等地区。调兵山做网站价格咨询:18982081108首先复习一些指针的基础知识点:
接下来开始正式的指针进阶学习。
1. 字符指针顾名思义,指向字符的指针,用char*来表示。例如char* p1 = "A",那么指针p1指向的就是字符常量A的地址。
在进阶学习中,我们要知道的是当有字符指针char* p2 = "Apple",此时的字符指针指向的是首字符“A”的地址,而不是字符串“Apple”放到p2里了。
掌握以上知识点后,我们来分析下面这道例题:
#includeint main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";
const char* str3 = "hello bit.";
const char* str4 = "hello bit.";
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;
}
题目要求判断最终打印结果是什么。首先看代码开头定义的四个变量,
指针数组是用来存放指针的数组,比如int* a[10], char** b[20];
数组指针是指向一个数组的指针,比如int (*p)[10];
接下来我们再明确一下数组指针的表达方式。int* p[10] 和int (*p)[10],前者是指针数组,后者却是数组指针。仔细观察后者写法,由于" [ ] "的优先级比“ * ”高,所以必须将*p先用括号括起来变成指针,再和[10]结合,变成指向有10个int元素的数组的指针,指针类型为int(*)[10]——指向有十个元素的整型数组的指针(否则*会先和int结合,变成整形指针数组)。
(1)数组名a不被看成首元素地址的情况虽然老生常谈,不过后期这个知识点也很重要。情况一共两种:
数组指针指向一个一维数组时,可以写成代码如下:
char a[5] = "hello";
char(*p)[5] = &a;
int i = 0;
for (i = 0; i< 5; i++)
{
printf("%c", *(*p+i));
//*p先拿到了数组的地址,*p+i实现遍历每个数组元素的地址,*(*p+i)解引用
//和前面所说的*(p+1)--步长为1个数组的大小,不一样
}
return 0;
但其实在一维数组的使用中,我们不常使用数组指针。就像上面这种情况,使用一个一维指针*p进行遍历会更加方便易懂。数组指针更多的是应用在二维及以上数组之中,接收从其他函数传来的数组首地址。如下代码:
void print(char(*p)[5], int row, int col)
//这里的[5]不能省略
//用数组指针p来接受二维数组,(*p)[5]将会接收二维数组的第一行一维数组的地址
{
int i = 0, j = 0;
for (i = 0; i< row; i++)
{
for (j = 0; j< col; j++)
{
printf("%c", *(*(p + i) + j));
//*(p+i)得到第i行形成的一维数组的地址,*(p+i)+j 得到第i行第j列元素的地址
//*p+i是得到数组的首地址再加i,每次i++会跨过一个元素的步长
//*(p+i)是先加i再解引用得到对应的数组地址,每次i++会跨过一个数组的步长
}
printf("\n");
}
}
int main()
{
char arr[3][5] = { "hello","abcde","thank" };
print(arr, 3, 5);
return 0;
}
由抽象过渡到具体实践,数组指针也可以应用在“给名字排序”等等的实验之中。例如下面这个:
//要求:给20个英文名字排序
void my_cmp(char(*np)[10])
{
int i = 0;
int j = 0;
char tmp[20] = { 0 };
for (i = 0; i< 20; i++)//冒泡法实现姓名排序
{
for (j = 0; j< (19 - i); j++)
{
if (strcmp(*(np + j), *(np + j + 1)) == 1)
{
strcpy(tmp, *(np + j));
strcpy(*(np + j), *(np + j + 1));
strcpy(*(np + j + 1), tmp);
}
}
}
}
int main()
{
int i = 0;
char name[20][10];
char(*np)[10] = &name;
//数组指针指向name第一行数组的地址
printf("请输入20个英文名字:\n");
for (i = 0; i< 20; i++)
{
scanf("%s",name[i]);
//这里不能写成scanf("%s",*np++)
//因为np作为指针,它指向的是存储在内存某地址中的数值
//所以可以把*np看作常量,常量是不能进行*np++或者(*np)++的
}
my_cmp(np);//括号里换成name也可以
printf("//排序后的结果为//\n");
for (i = 0; i< 20; i++)
{
printf("%s ",name[i]);
}
return 0;
}
(2)指针数组的使用指针数组,使用在一维数组情况上的情况如下:
int a = 11;
int b = 22;
int c = 33;
int* pa[3] = { &a,&b,&c };
//要将指针数组里每个元素都分配上地址
int i = 0;
for (i = 0; i< 3; i++)
{
printf("%d ", *pa[i]);//*(pa[i])
}
return 0;
和数组指针类似,指针数组在一维数组的使用上总会显得比较繁琐,它在模拟二维数组等应用上面才展现出了真正效果:
char* p[3] = { "really","okay","I'm fine" };
int i = 0, j = 0;
for (i = 0; i< 3; i++)
{
for (j = 0; *(p[i] + j )!= '\0'; j++)
{
printf("%c", *(p[i] + j));
//p[i]是第i个字符数组的首元素地址,
//p[i]+j就是第i个数组里第j个元素的地址
}
printf("\n");
}
//该指针数组实现了将二维数组降维,将其分成3个一维数组表示出来
//从这个实验还可以看出,指针数组相比较二维数组还可以节省内存空间
return 0;
总结(源自百度百科):指针数组的元素个数和二维数组的行数相同;数组指针的大小和二维数组整体大小相同,数组指针的元素个数和二维数组的列数相同。
3. 数组参数,指针参数 (1)数组部分传参这个部分在没有B站听网课之前困扰了我很久...所以基础知识就不能一知半解地放掉。首先是对于一维数组传参的几种情况进行分析
void test(int arr[])//1.1
{}
void test(int arr[10])//1.2
{}
//一维数组传参时,函数形参可以省略数组个数,即arr[]或者arr[10]皆可
//因为形参本身就不会创建一个10个元素的数组,形参接收到的只会是首元素地址
void test(int* arr)//1.3
{}
//使用一个一级指针正好就能去接收实参传过来的首元素地址
void test2(int* arr[])//2.1
{}
//同理,写成int* arr[10]亦可
void test(int** arr)//2.2
{}
//实参是一级指针,传过去首地址后要用二级指针接收地址
int main()
{
int arr[10] = { 0 };//1
int* arr2[20] = { 0 };//2
test(arr);
test2(arr2);
return 0;
}
以此类推,二维数组传参的思路和一维数组的情况差不多,不同之处在于二维数组的形参不能省略列数。比如实参为int a[2][3],那么接收的形参就不能将列数省略:int a[ ][3]。而当我们理解了指针数组和数组指针后,就可以进一步研究用指针参数接受二维数组的情况:
void test(int *arr)
{}
//上式形参无效
//test(arr),实参传过去的是首元素地址,即第一行一维数组的数组地址
//int*只能接受整形地址,不匹配
void test(int* arr[5])
{}
//上式形参无效
//int* arr[5]是一个指针数组,其中每个元素要接受的也都是整型地址
//而实参传过去的首数组地址既不满足有5个元素地址,也不是整型。不匹配
void test(int (*arr)[5])
{}
//上式正确
//int (*arr)[5]表示数组指针,接受的是有5个元素的数组类型
void test(int **arr)
{}
//上式形参无效
//传送过去的数组地址,不能用二级整形指针接收
int main()
{
int arr[3][5] = { 0 };
test(arr);
return 0;
}
(2)指针部分如果参数是一级指针*p,那么它可以接收的实参类型有一个变量的地址(eg. int a; 传参时--&a),或者一个一级指针(eg. int *p=&a; 传参时--p)。
同理,如果参数是二级指针**p,那么它可以接收的实参类型有一个一级指针的地址,或者一个二级指针。(如果是一个一级指针数组,传数组首地址过去也是可以的)
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流