【C语言】数组和指针的关系

一、一维数组和指针之间的关系

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));
		}
	}
	
}
  • 22
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值