一、一维数组和指针之间的关系
1、小结
结论一:
数组名出现在表达式中代表该数组首元素的地址
数组名相当于是个指针,一个指向本数组首元素地址的指针
结论二:
数组名前面&,表示的是指向整个数组的一个指针(数组指针)
2.int类型一维数组和指针的关系
例如:
int a[10]={11,22,33,456};
(1)访问数组的方法
第一种:数组名[下标]
a[1];
第二种: *(数组名+1)
*(a+1);
第三种:引入单独的指针,指向数组的首元素
int *p=a; //a等价于&a[0]
p[0]; //等价于a[0]第一个元素
p[1]; //等价于a[1]第二个元素
*(p+2); //等价于a[2]第三个元素
for(i=0; i<10; i++)
printf("%d\n",p[i]);
printf("%d\n",*(p+i));
printf("%d\n",*(a+i));
printf("%d\n",a[i]);
(2)两个指针相减
表示数组中两个指针之间间隔了多少个数据
int a[10]={11,22,33,456};
int *p1=a;
int *p2=&a[7];
注意:经典错误理解成直接用地址值做减法
(3)关于一维数组名的几种写法(重点理解每种写法的含义)
a int *类型的指针
&a 数组指针
a[0] 非指针,数组首元素值
&a[0] 数组首元素的地址
a+1 加类型的大小 4个字节
&a+1 加的是整个数组的大小
a[0]+1 把a[0]的值加1
&a[0]+1 加类型的大小 4个字节
3.char类型一维数组和指针的关系
例如:
char a[10]="hello";
(1)访问数组的方法
第一种:数组名[下标]
a[1];
第二种: *(数组名+1)
*(a+1);
第三种:引入单独的指针,指向数组的首元素
char *p=a; //a等价于&a[0]
p[0]; //等价于a[0]第一个元素
p[1]; //等价于a[1]第二个元素
*(p+2); //等价于a[2]第三个元素
for(i=0; i<10; i++)
printf("%c\n",p[i]);
printf("%c\n",*(p+i));
printf("%c\n",*(a+i));
printf("%c\n",a[i]);
(2)两个指针相减
表示数组中两个指针之间间隔了多少个数据
注意:经典错误理解成直接用地址值做减法
(3)关于一维数组名的几种写法(重点理解每种写法的含义)
a char *类型的指针
&a 数组指针
a[0] 非指针,数组首元素值
&a[0] 数组首元素的地址
a+1 加类型的大小 1个字节
&a+1 加的是整个数组的大小
a[0]+1 把a[0]的值加1
&a[0]+1 加类型的大小 1个字节
二、数组指针和指针数组
1.数组指针(中心词是指针)
(1)概念
int *p; int类型指针
char *p; char类型指针
数组 *p; 数组类型指针 --》数组指针
指向某个数组的指针
类型 (*指针名)[数组元素个数]
(2)如何定义数组指针
int a[10];
char b[15];
int c[10];
int (*p)[10]=&a; //定义了 int[10]类型的数组指针,指向a
p=&c; //指向c
char (*q)[15]=&b; //定义了 char[15]类型的数组指针,指向b
2.指针数组(中心词是数组)
(1)概念
数组中存放的全部都是指针,这种数组就叫做指针数组
类型 数组名[元素个数]
情况1:类型是指针 --》这种数组叫做指针数组
int *buf[10];
情况2:类型非指针 --》这种数组就是我们前面学习过的普通类型的数组
int buf[10];
int a[10]; //10个int
char b[5]; //5个char
int *c[3]; //3个int *
char *d[4]; //4个char *
(2)如何定义指针数组
指针类型 数组名[数组元素个数];
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
数组指针和指针数组
1.学习要点:当成语文的阅读理解,掌握中心词就能搞定问题
数组指针 -->中心词是指针,前面的数组用来修饰
概念: 只要一个指针指向整数的地址,我们就把这个指针叫做int *
只要一个指针指向字符串的地址,我们就把这个指针叫做char *
只要一个指针指向float的地址,我们就把这个指针叫做float *
只要一个指针指向整个数组的地址,我们就把这个指针叫做数组指针
数组类型 (*p)[数组元素]=&数组名
公式: 类型名 *指针名=变量;
int a;
int *p=&a; //整型指针
类型名 int
指针名 p
变量 &a
int buf[10];
int (*q)[10]=&buf;
类型名 int[10]
指针名 q
变量 &buf
char buf1[7];
char (*q)[7]=&buf1;
float buf2[3];
float (*q)[3]=&buf2;
double buf3[5];
double (*q)[5]=&buf3;
int buf4[6];
int (*q)[6]=&buf4;
2.指针数组 -->中心词是数组,指针用来修饰的
概念: 只要一个数组专门用来存放指针,我们就把这个数组叫做指针数组
只要一个数组专门用来存放int,我们就把这个数组叫做int数组
只要一个数组专门用来存放float,我们就把这个数组叫做float数组
举例:
int buf1[5]; //普通数组
int *buf2[4]; //指针数组,最多存放4个int *
char buf3[10]; //普通数组
char *buf4[10]; //指针数组,最多存放10个char *
*/
int main()
{
int buf[8];
//定义数组指针
int (*p)[8]=&buf; //p就是数组指针
//数组指针有啥用呢,如何使用呢? -->二维数组中会用到
printf("数组指针p最开始的地址: %p\n",p);
printf("数组指针p+1的地址: %p\n",p+1); //加的是类型的大小 int[8] 32个字节
//定义指针数组
int n1=12;
int n2=89;
int *p1=&n1;
int *p2=&n2;
int *otherbuf[5]; //otherbuf是数组的名字,该数组最多可以存放5个int *
//如何使用指针数组呢? -->很简单,你想想普通数组你是怎么用的?
otherbuf[0]=p1;
otherbuf[1]=p2;
return 0;
}
三、字符串常量和字符串变量
知识点1:如何区分什么是字符串常量,什么是字符串变量?
答案: 字符串常量只能在如下几种情况出现
情况1: char *s=“hello”;
情况2: strcpy(buf,“hello”);
知识点2: 字符串常量和字符串变量有什么区别?
字符串常量不能修改,只能访问
字符串变量可以修改,也可以访问
float a=12.57;
if(a==12.57) //12.57是浮点型常量,C语言默认当成double类型来存储
printf("ok");
else
printf("no");
//执行结果: NO
int main()
{
//字符串变量
char buf[10]="hello";
//字符串常量
//char *s="hello";
char *s;
s="hello";
/*
证明: 字符串常量不能修改,只能访问
字符串变量可以修改,也可以访问
*/
//printf("修改之前buf is: %s\n",buf);
//buf[0]='y';
//printf("修改之后buf is: %s\n",buf);
//printf("修改之前s is: %s\n",s);
//s[0]='y'; //修改字符串常量导致段错误
//printf("修改之后s is: %s\n",s);
return 0;
}
四、二维数组和指针之间的关系
1、小结
结论一:
二维数组名出现在表达式中代表该数组首元素的地址
二维数组名相当于是个指针,一个指向本数组首元素地址的指针
把二维数组理解为特殊的一维数组
比如:
char a[3][20]; //理解为包含了3个 char[20]的数组
int b[7][15]; //理解为包含了7个 int[15]的数组
结论二:
二维数组名前面&,表示的是指向整个数组的一个指针(数组指针)
2.int类型二维数组和指针的关系
int a[7][10]={66,77,88,99};
(1)访问数组的方法
第一种:数组名[下标][下标]
a[i][j];
第二种: 用数组名来表示
*(*(a+i)+j) --》等价替换成 *(a[i]+j)
第三种:引入单独的指针,指向数组的首元素
int *p = &a[0][0];
int类型二维数组和指针的关系
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
/*
结论一:一维数组/二维数组名出现在表达式中代表该数组首元素的地址
二维数组名相当于是个指针,一个指向本数组首元素地址的指针
把二维数组理解为特殊的一维数组
比如:char a[3][20]; //理解为包含了3个 char[20]的数组
int b[7][15]; //理解为包含了7个 int[15]的数组
注意如下问题:二维数组和一维数组写法不同(用指针)
注意1: buf和一维数组不同
注意2: 通过指针访问二维数组有两种写法
写法一:通过int *访问
写法二:通过数组指针访问
*/
int main()
{
int i,j;
int buf[3][4]={12,78,96};
//定义int *访问二维数组
//假设你的思维切换过来: 数组名buf代表该数组首元素buf[0]的地址
//buf[0]观察发现是int[4]
//数组名buf代表该首元数组素buf[0]的地址,buf[0]观察发现是int[4],因此buf表示的就是一个指向int[4]类型的数组指针
//int *p=buf; //错误,完全照抄一维数组 incompatible pointer(不兼容)
//int (*p)[4]=buf; //正确的写法
int *p=&buf[0][0]; //正确的写法
// for(i=0; i<12; i++)
// {
// printf("*(p+%d) is: %d\n",i,*(p+i));
// printf("p[%d] is: %d\n",i,p[i]);
// }
//照抄原来数组名的写法
//for(i=0; i<3; i++) //行
//{
//for(j=0; j<4; j++) //列
//{
//正确的,以前没学指针就是这么写的
//printf("buf[%d][%d] is: %d\n",i,j,buf[i][j]);
//错误的: 此时p和buf不完全等价
//printf("p[%d][%d] is: %d\n",i,j,p[i][j]);
//}
//}
//此时q和buf完全等价
int (*q)[4]=buf;
for(i=0; i<3; i++) //行
{
for(j=0; j<4; j++) //列
{
//正确的,以前没学指针就是这么写的
//printf("buf[%d][%d] is: %d\n",i,j,buf[i][j]);
//正确的: 此时q和buf完全等价
//printf("q[%d][%d] is: %d\n",i,j,q[i][j]);
//正确的: 有点复杂,需要推导(用等价替换的思想推导)
//*(*(q+i)+j)-->*(q[i]+j)-->*(buf[i]+j)-->*(&buf[i][0]+j)
printf("*(*(q+%d)+%d) is: %d\n",i,j,*(*(q+i)+j));
printf("*(*(buf+%d)+%d) is: %d\n",i,j,*(*(buf+i)+j));
}
}
}
(2)两个指针相减
表示数组中两个指针之间间隔了多少个数据
注意:经典错误理解成直接用地址值做减法
char buf[5][10]={"hello","world","china"};
char *p=&buf[1][3];
char *q=&buf[2][1];
printf("q-p is:%d\n",q-p); //间隔了多少个元素---- 8
(3)关于有二维数组名的几种写法(重点理解每种写法的含义)
a 二维数组首元素的地址 --》 a[0]的地址,数组指针 int (*p)[10]
&a 数组指针 int (*p)[7][10]
a[0] 第一个一维数组int[10]的名字,表示该数组首元素a[0][0]的地址 int *
&a[0] 数组指针 int (*p)[10]
a[0][0] 非指针
&a[0][0] int *
a+1 加类型的大小 int[10]大小
&a+1 加的是整个数组的大小,int[7][10]大小
a[0]+1 4个字节
&a[0]+1 加类型的大小 int[10]大小
a[0][0]+1 把数据加1
&a[0][0]+1 4个字节
3.char类型二维数组和指针的关系
char a[3][10]={"hello","china","nihao"};
(1)访问数组的方法
第一种:数组名[下标][下标]
a[i][j];
第二种: 数组名当成指针
*(*(a+i)+j)
第三种:引入单独的指针,指向数组的首元素
(2)两个指针相减
表示数组中两个指针之间间隔了多少个数据
注意:经典错误理解成直接用地址值做减法
(3)关于有二维数组名的几种写法(重点理解每种写法的含义)
a 二维数组首元素 的地址 --》 a[0]的地址,数组指针 char(*p)[10]
&a 数组指针 char (*p)[3][10]
a[0] 第一个一维数组char[10]的名字,表示该数组首元素a[0][0]的地址 char *
&a[0] 数组指针 char (*p)[10]
a[0][0] 非指针
&a[0][0] char *
a+1 加类型的大小 char[10]大小
&a+1 加的是整个数组的大小,char[3][10]大小
a[0]+1 1个字节
&a[0]+1 加类型的大小 char[10]大小
a[0][0]+1 把数据加1
&a[0][0]+1 1个字节
例子:
对二维数组名的理解
int buf[4][5]
buf:
数组名出现在表达式中,代表该数组首元素地址, buf首元素的地址是buf[0],buf[0]的类型是int [5], 即 buf 出现在表达式代表的是一个指向int [5]的数组指针。
数组指针解引用的写法
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
int main()
{
//前面的写法
int buf[5]={15,26};
//int *p=buf;
//*p=56; //等价p[0]=56 buf[0]=56
//偷懒的写法
int (*p)[5]=&buf;
//错误的
//*p=56; //等价替换 *&buf=56; --->buf=56;
//正确的
**p=56; //等价替换 **&buf=56; --->*buf=56;-->buf[0]=56;
printf("buf[0] %d\n",buf[0]);
题目1: *(*p+i) //是否正确,如果正确表示什么意思
*(*&buf+i)-->*(buf+i)-->buf[i]-->数组下标为i的元素
题目2:
int other[4][5]={45,96,789,2};
int (*q)[4][5]=&other;
*(*q+1) //是否正确,如果正确表示什么意思
*(*&other+1)-->*(other+1)-->other[1]-->是个&other[1][0]-->是int *
*(**q+1) //是否正确,如果正确表示什么意思
*(**&other+1)--> *(*other+1)-->*(*指向int[5]指针+1)-->*(int类型的指针+1)-->就是96
*(*(*q+1)) //是否正确,如果正确表示什么意思
*(*(*&other+1))--> *(*(other+1))-->*(other[1])-->*(&other[1][0])-->other[1][0]
}
指针访问二维数组
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
int main()
{
int i,j;
char buf1[7][10]={"hello","world","china"}; //buf1 char (*p)[10]=buf1
float buf2[3][6]={12.5,63.5,89.7}; //buf2 float (*q)[6]=buf2;
//方法1:通过char *访问buf1
//方法1:通过float *访问buf2
// char *p=&buf1[0][0];
// for(i=0; i<70; i++)
// {
// printf("*(p+%d) is:%c\n",i,*(p+i));
// printf("p[%d] is:%c\n",i,p[i]);
// }
// float *q=&buf2[0][0];
// for(i=0; i<18; i++)
// {
// printf("*(q+%d) is:%f\n",i,*(q+i));
// printf("q[%d] is:%f\n",i,q[i]);
// }
//方法2:通过char (*p)[10]访问buf1
//方法2:通过float (*q)[6]访问buf2
char (*p)[10]=buf1;
for(i=0; i<7; i++)
{
for(j=0; j<10; j++)
{
printf("p[%d][%d] is: %c\n",i,j,p[i][j]);
printf("*(*(p+%d)+%d) is: %c\n",i,j,*(*(p+i)+j));
}
}
float (*q)[6]=buf2;
for(i=0; i<3; i++)
{
for(j=0; j<6; j++)
{
printf("q[%d][%d] is: %f\n",i,j,q[i][j]);
printf("*(*(q+%d)+%d) is: %f\n",i,j,*(*(q+i)+j));
}
}
}