指针数组和数组指针
目录
一、指针和数组的区别
二、指针数组和数组指针
一、指针和数组的区别
1、例:计算一个字符串里面的字符个数,打开Oracle VM VirtualBox软件,输入代码,
代码如下:
#include <stdio. h>
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 <stdio. h>
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个元素的数组,所以它是数组,数组类型不是整型,有*是指向整型变量的指针,所以在内存中的定义是每一个数组的元素,都是一个整型指针变量。
下标 |
0 |
1 |
2 |
3 |
4 |
元素 |
Int* |
Int* |
Int* |
Int* |
Int* |
结论:指针数组是一个数组,每个数组元素存放一个指针变量。
指针数组如何初始化呢?代码如下:
#include <stdio . h>
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", *p1[i]);
}
return 0 ;
}
[ fishc@localhost s1le23]$ gcc test2.c && ./a . out
1
2
3
4
5
指向字符指针时的代码如下:
#incLude <stdio.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 <stdio. h>
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