开发者学堂课程【你的第一门 C 语言课:指针数组和数组指针】学习笔记,与课程紧密联系,让用户快速学习知识
课程地址:https://developer.aliyun.com/learning/course/444/detail/5473
指针数组和数组指针
目录
一、指针和数组的区别
二、指针数组和数组指针
一、指针和数组的区别
1、例:计算一个字符串里面的字符个数,打开 Oracle VM VirtualBox 软件,输入代码,
代码如下:
#include
int main( )
{
char str[] = "I love FishC. com!";
int count=0;
定一个变量用来计算这个字符的个数
while (*str++ != '\0' )
{
count++ ;
}
Printf("
总共有
%
d个字符
!\n",count );
打印结果
return 0;
}
[fishc@localhost s1e23]$ vi test1.c
[fishc@localhost sle23]$ gcc test1.c && ./a. out
test1.c: In function ' main' :
test1.c:8: error: lvalue required as increment operand
指针运算符的操作对象操作数必须是一个左值。
[fishc@localhost sle23]$
2、str 必须是一个 lvalue,str 是数组的名字,数组名是不是左值呢?
从定义上来看,C 语言的术语 Ivalue 指用于识别或定位一个存储位置的标识符。
( 注意:左值同时还必须是可改变的)数组名定义的就是数组的位置,数组名是不可修改的,它是一个地址常量,字符串的地址,所以要对代码进行修改,
修改后的代码如下:
#include
int main( )
{
char str[] = "I love FishC. com!";
Char *
target
=
str
;
指向字符串
int count=0;
while (*target++ != '\0' ) 用 target 进行处理,这是一个复合语句,复合表达式,操作数有两个运算符对它进行作用,一个是自增运算符,一个是取值运算符,运算符的优先级,自增运算运算符比取值运算符高一个级别,
所以先运算 target++,后缀运算符有一个特性,作用效果要在下一条语句才会显示,虽然是自增,但是这一句还是使用 target 本身的值,取*target 值跟\0匹配,是否等于字符串的结束符,如果不是就加1,如果是就退出循环,再下一次碰到的时候,target 是++后的结果,以此类推,计算出总共有多少个字符。
{
count++ ;
}
Printf("
总共有
%
d个字符
!\n",count );
return 0;
}
[ fishc@localhost s1e23]$ gcc test1.c && ./a. out
总共有17个字符!
3、最后可以从这个程序看出指针变量跟字符串名字有什么区别?同样都是指向地址,但是指针变量是一个左值,字符串名字是地址常量,不是左值,因为++运算符要对 target 进行赋值,必须是可改变的,target 本身指向1,++后指向2,再++指向3,如此反复。
4、结论:数组名只是一个地址,而指针是一个左值。
二、指针数组和数组指针
1、指针数组是数组,数组指针是指针。
2、例:int *p1[5];int (*p2)[5];哪个是指针数组,哪个是数组指针?
(1)int *p1[5]是指针数组
从运算符的优先级和结合性入手,定义同时有取值运算符和下标运算符作用于变量p1,数组下标比取值运算符级别高,所以 p1[5]先结合,p1被定义为具有5个元素的数组,所以它是数组,数组类型不是整型从运算符的优先级和结合性入手,定义同时有取值运算符和下标运算符作用于变量p1,数组下标比取值运算符级别高,所以
下标 |
0 |
1 |
2 |
3 |
4 |
元素 |
Int* |
Int* |
Int* |
Int* |
Int* |
结论:指针数组是一个数组,每个数组元素存放一个指针变量。
指针数组如何初始化呢?代码如下:
#include
int main( )
{
int a
=
1;
Int
b=
2;
int
c=3;
int d
=4;
Int
e=5;
int *p1[5] =
{
&a, &b, &c, &d, &e];
int i;
for(i=0;i<5;i++)
{
printf("%d
\
n", *p
1
[i]);
}
return 0 ;
}
[ fishc@localhost s1le23]$ gcc test2.c && ./a . out
1
2
3
4
5
指向字符指针时的代码如下:
#incLude <
s
tdio
.
h>
int main( )
{
char *p1[5] = {
"让编程改变世界-
-
鱼C工作室"
,
"Just do it
--
NIKE",
"一切皆有可能
--
李宁"
,
"永不止步
--
安踏"
,
"One more thing..
--
苹果"
};
int i;
for(i=0;i<5;i++)
{
printf("%s\n", p1[i])
;
}
return 0 ;
}
[ fishc@localhost s1le23]$ gcc test3.c && ./a . out
让编程改变世界-
-
鱼C工作室
Just do it
--
NIKE
一切皆有可能
--
李宁
永不止步
--
安踏
One more thing..
--
苹果
(2)int (*p2)[5]是数组指针
从运算符的优先级来看,它们在同一级,所以从结合性来看,左到右,就是左边的先结合,p2先被定义为指针变量,指针变量的类型指向元素的类型,所以int 定义的是数组元素的类型。
下标 |
0 |
1 |
2 |
3 |
4 |
元素 |
Int |
Int |
Int |
Int |
Int |
结论:数组指针是一个指针,它指向的是一个数组。
数组指针如何初始化呢?
warning 是它认为代码有问题,但还是会尊重程序员进行编译执行,error 就是编译不成功,p2是一个指针所以要给它一个地址,编译器提醒,指针类型初始化不一致,数组名是数组第一个元素的地址,
正确代码如下:
#include
int main( )
{
int temp[5] = {1, 2, 3, 4, 5};
int (*p 2)[5]=& temp;
指针指向的是数组一个的元素的地址,指向整型变量的指针,指向第一个元素,而不是数组,虽然数组第一个元素的地址等于数组名等于数组的地址,但是概念不同,数组的所有元素都是挨个存放的,当知道第一个元素的地址时,要变量它所有元素也是没有问题的。
所以这里不是要一个变量的地址,而是要一个真正的身份,数组把它当作一个整体,取出这个数组的地址,才是这个数组指针想要的内容。
int i;
for(i=0;i<5;i++)
{
printf("%d\n", *(*p2+ i)); *p2
表示数组的地址
,
再
+
i是取出它的值
}
return 0 ;
}
[fishc@localhost s1e23]$ gcc test4.c && ./a. out
1
2
3
4
5