//-----------------------------一维指针数组
什么是指针数组?
是一个数组! 里面的数组元素都是地址
int a = 10,b = 15,c = 20;
int *pa[3] = {&a,&b,&c}; //指针数组
类型说明符 *数组名[数组长度]
int *pa[3] = {a[0],a[1]};
int arr[2][3] = {1,2,3,4,5,6};
//定义了一个指针数组
int *pa[2] = {arr[0],arr[1]};
for(int i = 0;i < 2;i++){
for(int j = 0;j<3;j++){
*(*(pa+i)+j) == *(pa[i]+j)
}
}
//-----------------------------数组指针
怎么理解数组指针?
指向数组的指针
一个变量有地址,一个数组包含若干元素,每个数组元素都有相应的地址
指针变量可以指向数组元素(把某一元素的地址放到一个指针变量中)
所谓数组元素的指针就是数组元素的地址
可以用一个指针变量指向一个数组元素
注意:
1)数组名a不代表整个数组,只代表数组首元素的地址。
“p=a;”的作用是“把a数组的首元素的地址赋给指针变量p”,而不是“把数组a各元素的值赋给 p”
怎么使用?
如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素,p-1指向同一数组中的上一个元素。
结论: 引用一个数组元素,可用下面两种方法:
(1)下标法,如a[i]形式
(2)指针法,如*(a+i)或*(p+i)
(3)a是常量(a++错误),p是变量(p++正确)
int arr[3] = {1,2,3};
//指向一维数组就是一维数组的指针
int *p = arr; //指向数组的指针
//一维数组指针
*(p+i) == *(arr+i) == arr[i]
有一个整型数组a,有10个元素,要求输出数组中的全部元素
解题思路:
引用数组中各元素的值有3种方法:
(1)下标法;
(2)通过数组名计算数组元素地址,找出元素的值;
(3)指针
//-------------------------------用数组名访问二维数组
int arr[3][4]={
{1,3,5,7}, ---> arr[0] 第0个一维数组
{9,11,13,15},---> arr[1]
{17,19,21,23}---> arr[2]
};
arr代表指向第0个元素的地址 &arr[0] 第一行元素的地址 行指针
arr+1代表指向第一个元素的地址 &arr[1]
arr+2代表指向第二个元素的地址 &arr[2]
arr+i代表指向第i个元素的地址 &arr[i]
arr[0]代表arr[0][0]的地址
arr[0]+1代表arr[0][1]的地址
arr[0]+2代表arr[0][2]的地址
arr[0]+3代表arr[0][3]的地址
&arr == arr == &arr[0] == arr[0] == &arr[0][0] ---> 数组的首地址
&arr --> 整个数组的地址 +1(越界)
arr --> 指向数组第0行的地址 &arr[0]
&arr[0] --> 指向数组第0行的地址
arr[0] --> 第0行的内容/二维数组的第一个一维数组 指向这个一维数组第一个元素的地址 == &arr[0][0]
&arr[0][0] 整个二维数组第1个一维数组里面第一个元素的地址
int a[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
访问 第一行的第0个元素地址表示:
a + 1 = &a[1] = a[1] = &a[1][0] = *(a + 1)
获取第一行的第0个元素值的方式:
*a[1] = a[1][0] = **(a + 1)
//-------------------------------普通指针访问二维数组
用普通指针指向二维数组,也能遍历数组的值
这种写法主要是利用了二维数组逐行,每行逐个元素存储的原理
会报警告,不建议这样写
那么我们有应该怎么写呢? 看下面---二维数组指针
//----------------------------二维数组指针
怎么理解二维数组指针
指向二维数组的指针变量
数据类型 (*指针变量名)[二维数组列数];
int a[2][3] = {1,2,3,4,5,6};
int (*pa)[3] = a;
*(*(pa+i)+j) == *(*(a+i)+j) == *(a[i]+j)
//---------------------------指针数组和二维数组指针的区别
int *pa[3]={&a,&b,&c};
int *pa1[2]={a[0],a[1]}
pa,pa1都是一个指针数组
int (*pa)[3]; //二维数组指针
/*
1、一维数组指针
指向一维数组的指针
int a[5] = {1,2,3,4,5};
int *p = a;
2、二维数组指针
指向二维数组的指针
int arr[1][3] = {1,2,3};
int (*p)[3] = arr;
注意:
数组名a不代表整个数组,只代表数组首元素的地址。
3.指针数组:数组的每一个元素都是一个指针
或者存放指针的数组,就是指针数组
int a=3,b=4,c=5;
int *pa[3]={&a,&b,&c};
int a[2][3]={{1,2,3},{4,5,6}};
int *pa[2]={a[0],a[1]};
*/
//------------------------------指针变量之间的运算
前提:两个指针必须指向同一个数组
运算:减法
实质:计算两个指针之间关系,判断指针的位置
两指针变量相减所得之差是两个指针所指数组元素之间相差的元素个数。
进行关系运算
p1>p p1的地址高于p
p1<p p1的地址低于p
指针之间可以相减,但不可以相加(相加无意义)
空指针是由对指针变量赋予0值而得到的。
//-------------字符串指针
定义字符串的方法:
1)字符数组
char string[]=”I love China!”; printf("%s\n",string);
说明:和前面介绍的数组属性一样,string是数组名,它代表字符数组的首地址。
2)字符串指针指向字符串
char *变量名="字符串内容"; //"字符串内容"是常量
char *str="abc"
char ch = 'b';
char *p1 = &ch;
字符串指针变量的定义说明与指向字符变量的指针变量说明是相同的。只能按对指针变量的
赋值不同来区别.
对指向字符变量的指针变量应赋予该字符变量的地址。
字符数组 -----> 保存在栈里
字符指针 ----> 常量区(只读)
char *str = "apple"; //指针变量/变量 保存在栈区 指向了常量区的字符串(首地址)
1、char *ch = "abcde"; ch+1表示的是什么? *(ch + 1)表示的是什么?
2、char *ch1 = "12345"; 将*(ch1 +1) = '6';赋值正确吗?为什么?
3、char ch2[] = "abcde"; *(ch + 2) = '9';打印输出print("%s",ch2)的结果是什么?
不能直接接收键盘输入
char *str;
scanf("%s",str); //str是个野指针
但是
1)char ch[100];
char *str = ch;
scanf("%s",str);
字符串指针变量与字符数组的区别
用字符数组和字符指针变量都可实现字符串的存储和运算。
字符串指针变量本身是一个变量,用于存放字符串的首地址。
而字符串本身是存放在以该首地址为首的一块连续的内存空间中并以‘\0’作为串的结束。
字符数组是由于若干个数组元素组成的,它可用来存放整个字符串。
1、区别一,能否重新赋值问题
对字符串指针方式
char *ps="C Language";
可以写为:
char *ps;
ps="C Language";
而对数组方式:
char st[]={"C Language"};
st = "xxx";
不能写为:
char st[20];
st={"C Language"};
2、区别二,存储的区别
而只能对字符数组的各元素逐个赋值。
当一个指针变量在未取得确定地址前使用是危险的,容易引起错误。但是对指针变量直接赋值是
可以的。因为C系统对指针变量赋值时要给以确定的地址。
因此,
char *ps="C Langage";
或者
char *ps;
ps="C Language";
//----------------
第一层: 你能定义字符串
第二层:用字符数组定义字符串能改字符串内容(栈区)
用指针的方式定义字符串不能改字符串内容(常量区)
第三层:先定义后初始化字符问题
char str[]; str = "xxx" //错误
char *str; str = "xxx" //正确
//--------------------------指针和函数之间的关系
1)返回值是指针的函数 指针函数
char *getday(){
return "星期一";
}
2)函数指针
指向函数的指针
格式:返回值 (*指针变量名)(函数的参数);
定义函数
int sum(int a,int b){
return a+b;
}
格式一:int (*p1)(int a,int b); // 函数指针p1 只能指向返回值是int类型,并且有两个int 类型参数的函数。
格式二:int (*p2)(int,int);
技巧:
声明的格式:int sum(int a,int b);
int (*p3)(int a,int b) = sum;
p3 = sum;
//-----------递归函数
一个函数在它的函数体内调用它自身称为递归调用。这种函数称为递归函数。
递归函数构成条件
1)自己调用自己
2)存在一个条件能够让递归结束
3)能让问题的规模能够缩小
问题:
有5个人坐在一起,问第5个人多少岁?他说比第4个人大两岁。问 第4个人岁数,他说比第3个人大两岁。问第3个人,又说比第2个 人大两岁。问第2个人,说比第1个人大两岁。最后问第1个人, 他说是10岁。请问第5个人多大?
|