精华内容
下载资源
问答
  • C语言 指针数组的详解及对比 通俗理解数组指针指针数组 数组指针: eg:int( *arr)[10]; 数组指针通俗理解就是这个数组作为指针指向某一个变量。 指针数组: eg:int*arr[10]; 指针数组简言之就是存放指针数组...
  • C语言程序设计教案 章节名称 指向数组指针1 授课类型 理论 实验 ?理实一体 实训 实习 班级 地点 周次 星期 节次 授课进度 ?符合 超前 滞后 ?符合 超前 滞后 ?符合 超前 滞后 教学目标 知识目标 1.理解指向数组元素...
  • 只是为了说明用指向数组指针作函数参数而举的例子。用函数average求总平均成绩,用函数search找出并输出第i个学生的成绩。有些网上给出的方法有bug,这个是我自己修改过的程序。
  • #include int main(){ int a[5]; int *p,i; printf("please enter ten numbers:"); for(i=0;i;i++){ scanf("%d",&a[i]); } for(p=a;p<(a+5);p++) scanf("%d",*p); printf("\n"); ...
  • C语言指针引用数组

    千次阅读 2020-10-16 21:32:54
    前言:C语言指针玩的是什么,是内存,要想学好指针的小伙伴们要先对数据在内存中是怎么玩的做一番了解~       当在程序中定义一个变量时,系统会根据其数据类型为其开辟内存空间,...

    前言:C语言中指针玩的是什么,是内存,要想学好指针的小伙伴们要先对数据在内存中是怎么玩的做一番了解~

          当在程序中定义一个变量时,系统会根据其数据类型为其开辟内存空间,例如Visual C++为整型变量分配四个字节的空间,为单精度浮点型变量分配四个字节,为字符型变量分配一个字节,内存中每个字节都有自己独立且唯一的一个编号,这就是地址 ,如下图,系统为变量i分配了2000~2004的存储单元。

    在这里插入图片描述

     
    _访问变量的方式_有如下图两种:
          第一种直接访问方式,直接通过变量名访问,变量名与地址有一一对应关系,因此按此地址直接对变量i的存储单元进行访问;
          第二种间接访问方式,先通过i_pointer找到i的地址的位置,再通过i的所存地址的位置找到i的地址2000,随后对变量i进行存取操作。间接访问的方式就要用到指针,所谓指针(2000)即为一个变量的地址,指针变量(i_pointer)是存储这个地址的用来指向另一个对象的变量。

    关键字变量类型
    int整型变量
    char字符变量
    类型名*指针变量

    它们之间的关系为:指针变量的值是指针,指针是变量i的地址,变量i存放所需要存放的存储内容。
    图片的中*为取值运算符,*i_pointer表示对i_pointer中存放的地址进行取值,相当于 变量i。
     

    在这里插入图片描述

    指针的定义:

    基类型 *变量名
    例:int *p
          char *p
          float p
    注意 : 此时的
    与上文中提到的取值运算符并不是一个概念,此时的
    *意思是定义一个变量,这个变量是指针变量。

    指针的引用:

    对指针进行赋值:
    以下面程序为例:

    int *p;
    int a = 3;
    p = &a;
    *p = 2;

    p = &a(&为取地址符,意思是取变量a的地址赋给指针变量P)
    *p = 2(p上文中已经提到是对指针变量P中存储的地址进行取值p相当于变量a,对
    *p进行赋值即相当于对变量a进行赋值)

    指针变量做函数参数

    以定义两个变量a和b,使其值进行交换为例进行阐述

    #include<stdio.h>
    
    //值传递
    void swap1(int x, int y) {
    	int z;
    	z = x;
    	x = y;
    	y = z;
    }
    
    //地址传递 
    void swap2(int *p1, int *p2) {
    	int t = *p1;
    	*p1 = *p2;
    	*p2 = t;
    }
    
    /*
    错误,指针变量t所指向的内容不可预见,对*t赋值就是向一个未知存储单元赋值 ,可能操纵到有用信息,
    破坏系统的正常工作状态 ,这种指针叫做**野指针**;
    
    那么如何解决野指针危险性呢:
    可以对该指针进行初始化,使其指向NULL,NULL为地址为0的内存地址,在大多数操作系统上,该内存为操作系统保留,
    用户不可操控  
    */ 
    //void swap3(int *p1, int *p2) {
    //	int *t;
    //	*t = *p1;
    //	p1 = *p2;	//报错 
    //	p2 = *t;
    //}
    
    /*
    C语言中实参变量与形参变量之间的数据传递是单向的“值传递”方式。
    不能通过操作形参中指针变量的值企图改变实参中指针变量的值,但是可以通过形参接收到的实参传过来的地址
    对指针变量指向的值进行操作。
    */ 
    void swap4(int *p1, int *p2) {
    	int *t = NULL;
    	t = p1;
    	p1 = p2;
    	p2 = t;
    }
    
    int main() {
    	int a, b;
    	scanf("%d %d", &a, &b);
    	
    	swap1(a, b);
    	printf("%d %d\n", a, b);
    	
    	int *p1 = &a, *p2 = &b;
    	
    	swap2(p1, p2);
    	printf("%d %d\n", a, b);
    	
    	swap4(p1, p2);
    	printf("%d %d\n", *p1, *p2);	//注:在swap2()函数中,a b的值发生了交换 
    	
    	return 0;	
    }
    
    /*
    运行结果:
    1 3
    1 3
    3 1
    3 1
    */ 
    

    指针指向数组

    盆友们一定要记住这两句话再往下看***!!!***
    首地址:一段内存空间的第一个存储单元,而不是第一个字节;
    指针变量的加减:以指针指向的类型空间为单元进行偏移;

    以定义一个数组,输入数值,最后输出数组中所有元素为例进行阐述

    /*
    须知:
    1.单目运算符优先级比双目运算符高,同级下从右往左结合 
    2.*(p + i)等价于*(a+i)等价于a[i] 
    3.数组名为数组的首地址,即p = a相当于p = &a[0]
    4.p + 1指向数组中的下一个元素,加上的不是简单的字节数,而是定义的指针的基类型的字节数
    5.a[i]的[]为变址运算符,下标法中对下标的处理是转换成地址的,也是按照a + i计算地址,然后找出此地址单元中的值
    6.利用p++的指针自加操作,指针直接指向元素,不必每次都计算地址,比下标法和计算指针地址后再取值的方法快 
    7.a是一个类型为int *的指针常量,指向数组首个元素的地址,不能企图使用a++的方式便利数组中的元素 
    8.指针的加减运算往往作用在同一数组下的元素上,虽然指针变量可以指向数组元素以后的存储单元,但是得到的数据往往是
    不被我们所期待的数据,这种操作是毫无意义的 
    */
    #include<stdio.h>
    int main() {
    	int a[5];
    	
    	//下标法
    	for(int i = 0; i < 5; i++) 
    		scanf("%d", &a[i]);				//等价于scanf("%d", a + i);
    	int *p, *p1;
    	
    	p = a;								//等价于p = &a[0] 
    	p1 = &a[0];
    	
    	for(int i = 0; i < 5; i++)
    		printf("%d ", a[i]);
    	printf("\n");
    
    	//指针法
    	/*
    	p:a[0]的地址	*p:a[0]的值
    	*(p+1):a[1]的值
    	*(p+2):a[2]的值 
    	
    	p的值并未改变 
    	
    	test: 
    	#include<stdio.h>
    	int main() {
    		int a[5] = {1, 2, 3, 4, 5};
    		int *p = a;
    		printf("%d\n", p);
    		for(int i = 0; i < 5; i++) {
    			printf("%d ", *(p + i));
    		}
    		printf("\n%d\n", p);
    		
    		for(int i = 0; i < 5; i++) {
    			printf("%d ", *p++);
    		}
    		printf("\n%d\n", p);
    	} 
    	/*
    	运行结果:
    	6618608
    	1 2 3 4 5
    	6618608
    	6618628
    	*/
    	
    	*/
    			
    	for(int i = 0; i < 5; i++) 
    		printf("%d ", *(p + i));		
    	printf("\n");
    	
    	//a为指针常量不能改变,变的是 a + i本身 
    	for(int i = 0; i < 5; i++) 
    		printf("%d ", *(a + i));		
    	printf("\n");
    	
    	//指针p在不断移动,因此在学习的过程中要时刻注意指针的位置!!! 
    	for(int p = a; p < (a + 5); p++)
    		printf("%d ", *p); 
    	return 0; 
    }
    
    /*
    补充:
    1.由于在C语言编程系统中,对下标的处理是转换成地址的,因此, p[i]即被处理成*(p + i) 
    

    数组名做函数参数

    /*
    须知:
    1.数组名为数组首元素的地址,实参传递a传递给形参的是地址,形参需要用一个指针变量来接实参的地址
    2.C编译都是将形参数组名作为指针变量来处理的,也就是说,程序中形参的a[]的a实际上是一个指针,对a[]的操控实际上
    就是对指向实参中的数组进行操控
    3.上文中已经提到p[i]与*(p+i)无条件等价 
    */
    #include<stdio.h>
    
    void swap(int a[], int n) {
    	int h = 0, t = n - 1, m = (n - 1) / 2;
    	for(h; h <= m; h++) {
    		int tmp = a[h];
    		a[h] = a[t];		//根据须知3: a[h]等价于*(a+h) 
    		a[t] = tmp;
    		t--;
    	}
    }
    
    void swap1(int *x, int n) {
    	int *p, *i, *j;
    	i = x;
    	j = x + n - 1;
    	p = x + (n - 1) / 2;
    
    	for( ; i <= p; i++, j--) {
    		int tmp = *i;
    		*i = *j;
    		*j = tmp;
    	}
    }
    
    int main() {
    	int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    	for(int i = 0; i < 10; i++) 
    		printf("%d ", a[i]);
    	printf("\n"); 
    	swap(a, 10);
    	for(int i = 0; i < 10; i++) 
    		printf("%d ", a[i]);
    	printf("\n");
    		
    	swap1(a, 10);
    	for(int i = 0; i < 10; i++) 
    		printf("%d ", a[i]);
    	printf("\n");
    	return 0;	
    } 
    /*
    运行结果:
    0 1 2 3 4 5 6 7 8 9
    9 8 7 6 5 4 3 2 1 0
    0 1 2 3 4 5 6 7 8 9
    */ 
    

    指针指向 二维数组

    在这里插入图片描述

    a[3][4]数组的结构:
          三个一维数组
          四个int类型的元素

    **
    再次强调:
    1.指针变量的加减:以指针指向的类型空间为单元进行偏移;
    2.数组名代表数组元素的首地址

    a是二维数组名,指向的第一个存储单元是a[0]这个一维数组,a的类型是指向一维数组的指针常量, a+1即偏移一个一维数组;
    a[0],a[1], a[2]是一维数组名,代表一维数组中的元素的首地址,也就是说a[0]的值是&a[0][0],a[1]的值是&a[1][0],a[2]的值是&a[2][0]。    a[0],a[1], a[2]分别指向的第一个存储单元是a[0][0], a[1][0], a[2][0]这几个元素,它们的类型是指向元素的指针常量,a[0]+1即偏移一个元素;

    为了让大家看清除,博主以表格形式展示出来:

    首地址指向类型移动一位移动字节数
    二维数组的首地址aa[0]这个一维数组int(*)[4]a+116B
    以为数组的首地址a[0]a[0][0]元素int*a[0]+14B

     
     
     

    指针指向二维数组的各种表现形式

    #include<stdio.h>
    int main() {
    	int a[3][4] = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23};
    	/*
    	a是指向行的指针常量,代表二维数组的首地址,即首行的首地址,
    	a + 1:序号为 1的行的首地址
    	a + 2:序号为 2的行的首地址
    	
    	在行指针前面加一个 * ,则转换成列指针(列地址),指向一维数组的首地址 ;
    
    
    	*a:对第0行的地址进行取值,由于a并不是一个变量的存储单元,取值后得到一维数组的地址a[0]<->*(a+0)<->*a,指向列地址,即第0行一维数组的首地址 
    	*(a + 1): 第1行一维数组的首地址
    	*(a + 2): 第2行一维数组的首地址 
    	由于a[0] = *a, a[1] = *(a + 1), a[2] = *(a + 2),所以两种形式等价 
    	a[0]: 代表0行一维数组的首地址,指向0行0列元素地址 
    	a[1]: 代表1行一维数组的首地址,指向1行0列元素地址 
    	a[2]: 代表2行一维数组的首地址,指向2行0列元素地址 
    	
    	a[0] + 0: 代表0行0列元素的地址 
    	a[0] + 1: 代表0行1列元素的地址
    	a[0] + 2: 代表0行2列元素的地址 
    	
    	*(a[0] + 0): 0行0列元素的值,a[0][0],*(*(a + 0) + 0) 
    	*(a[0] + 1): 0行1列元素的值,a[0][1], *(*(a + 0) + 1)
    	*(a[0] + 2): 0行2列元素的值,a[0][2], *(*(a + 0) + 2)
    	
    	在列指针前面加一个 & , 则转换成行指针(行地址),行指针前面加上一个 &,则转换成指向整个数组的指针(表示为整个数组的地址),指向二维数组的首地址。 	
    	&a: 指向整个二维数组 
    	&a[0]: 指向第0行的一维数组 
    	&a[0][0]: 指向0行0列的元素,即指向a[0][0], 是a[0][0]这个元素的地址 
    	
    	*/ 
    	printf("%d %d\n", a, *a);			//a:表示0行首地址	  *a:表示0行0列元素的地址	二者的值一样,但是指针类型不同					 
    	printf("%d %d\n", a[0], *(a + 0));			 
    	printf("%d %d\n", &a[0], &a[0][0]);	 
    	printf("%d %d\n", a[1], a + 1);
    	printf("%d %d\n", &a[1][0], *(a + 1) + 0);
    	printf("%d %d\n", a[2], *(a + 2));
    	printf("%d %d\n", &a[2], a + 2);
    	printf("%d %d\n", a[1][0], *(*(a + 1) + 0));
    	printf("%d %d\n", *a[2], *(*(a + 2) + 0));
    	return 0;
    }
    
    /*
    运行结果:
    6618608 6618608
    6618608 6618608
    6618608 6618608
    6618624 6618624
    6618624 6618624
    6618640 6618640
    6618640 6618640
    9 9
    17 17
    */ 
    

    指向二维数组的指针变量

    #include<stdio.h>
    int main() {
    	int a[3][4] = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23};
    	
    	/*
    	指向数组元素的指针变量 
    	*/ 
    	int *p;
    	for(p = a[0]; p < a[0] + 12; p++) {
    		printf("%2d ", *p);
    		
    	}
    	printf("\n\n");
    	
    	/*
    	指向一维数组的指针变量
    	*/ 
    	int (*q)[4] = a;				//指针变量p指向4个整形元素的一维数组 
    	for(int i = 0; i < 3; i++) {
    		for(int j = 0; j < 4; j++) {
    			printf("%2d ", *(*(q + i) + j));
    		}
    	}
    	 
    	return 0;
    } 
    

    用指向数组的指针做函数参数

    #include<stdio.h>
    //指向变量的指针变量
    void avg(float *p, int n) {
    	float sum = 0, ans = 0;
    	float *p1 = p + 11;
    	for(p; p <= p1; p++)
    		sum = sum + *p;
    	ans = sum / n;
    	printf("%.2f\n", ans);
    }
    //指向一维数组的指针变量
    void search(float (*p)[4], int n) {
    	for(int i = 0; i < 4; i++) {
    		printf("%.2f ", *(*(p + n) + i));
    	}
    }
    int main() {
    	float score[3][4] = {78, 90, 89, 34, 91, 61, 71, 84, 67, 76, 100, 53};
    	avg(*score,12);	 
    	search(score, 2);		 
    	return 0;
    }
    

    指针指向 三维数组

    在这里插入图片描述

     

    a[2][3][4]数组的结构:
       两个二维数组
       三个一维数组
       四个int类型的元素

    首地址指向类型移动一位移动字节数
    aa[0]这个二维数组int(*)[3][4]a+148B
    a[0]a[0][0]这个一维数组int(*)[4]a[0]+116B
    a[0][0]a[0][0][0]元素int *a[0][0]+14B

     
     
     

    指针指向 多维数组

    原理与二维数组三维数组一样
    取元素的值:
    在这里插入图片描述

    展开全文
  • 一、C 语言数组指针指向数组指针) 二、C 语言字符串指针(指向字符串的指针) 三、C 语言指针数组(数组每个元素都是指针) 四、二维数组指针(指向二维数组的指针) 五、指针数组和二维数组指针的区别: ...

    目录

    一、C 语言数组指针(指向数组的指针)

    二、C 语言字符串指针(指向字符串的指针)

    三、C 语言指针数组(数组每个元素都是指针)

    四、二维数组指针(指向二维数组的指针)

    五、指针数组和二维数组指针的区别:

    六、常见指针变量的例子集合:见下图


    一、C 语言数组指针(指向数组的指针)

    定义数组时,要给出数组名和数组长度,数组名可以认为是一个指针,它指向数组的第 0 个元素。 在 C 语言中,我们将第 0 个元素的地址称为数组的首地址。 以上面的数组为例,下图是 arr 的指向:

    #include <stdio.h>
    int main(){
    int arr[] = { 99, 15, 100, 888, 252 };
    int len = sizeof(arr) / sizeof(int); //求数组长度
    int i;
    for(i=0; i<len; i++){
    printf("%d ", *(arr+i) ); //*(arr+i)等价于arr[i]
    }
    printf("\n");
    return 0;
    }
    
    运行结果:
    99 15 100 888 252

    ② 定义一个指向数组的指针:

    int arr[] = { 99, 15, 100, 888, 252 };
    int *p = arr;

           arr 本身就是一个指针,可以直接赋值给指针变量 p。 arr 是数组第 0 个元素的地址,所以 int *p = arr;也可以写作int *p = &arr[0];。也就是说, arr、 p、 &arr[0] 这三种写法都是等价的,它们都指向数组第 0 个元素,或者说指向数组的开头。
    ③ 两种方案来访问数组元素:
    1) 使用下标
    也就是采用 arr[i] 的形式访问数组元素。如果 p 是指向数组 arr 的指针,那么也可以使用 p[i] 来访问数组元素,它等价于 arr[i]。
    2) 使用指针
    也就是使用 *(p+i) 的形式访问数组元素。另外数组名本身也是指针,也可以使用 *(arr+i) 来访问数组元素,它等价于 *(p+i)。

    ④ 关于数组指针的谜题:

    *和++优先级(一样,从右往左)

    假设 p 是指向数组 arr 中第 n 个元素的指针,那么 *p++、 *++p、 (*p)++ 分别是什么意思呢?
           *p++ 等价于 *(p++),表示先取得第 n 个元素的值,再将 p 指向下一个元素。

           *++p 等价于 *(++p),会先进行 ++p 运算,使得 p 的值增加,指向下一个元素,整体上相当于 *(p+1),所以会获得第 n+1 个数组元素的值。
           (*p)++ 就非常简单了,会先取得第 n 个元素的值,再对该元素的值加 1。假设 p 指向第 0 个元素,并且第 0个元素的值为 99,执行完该语句后,第 0 个元素的值就会变为 100。

    二、C 语言字符串指针(指向字符串的指针)

    ① 字符串数组:

    char str[] = "http://c.biancheng.net";
    int len = strlen(str), i;
    //直接输出字符串
    printf("%s\n", str);
    //每次输出一个字符
    for(i=0; i<len; i++){
    printf("%c", str[i]);
    }

    ② 字符串指针:

    C 语言还支持另外一种表示字符串的方法,就是直接使用一个指针指向字符串:

    char *str = "http://c.biancheng.net";
    
    char *str;
    str = "http://c.biancheng.net";
    
    上面两个相同

    字符串中的所有字符在内存中是连续排列的, str 指向的是字符串的第 0 个字符。

    char *str = "http://c.biancheng.net";
    int len = strlen(str), i;
    
    //直接输出字符串
    printf("%s\n", str);
    
    //使用*(str+i)
    for(i=0; i<len; i++){
    printf("%c", *(str+i));
    
    //使用str[i]
    for(i=0; i<len; i++){
    printf("%c", str[i]);
    }
    
    以上三种均可

    :都可以使用*或[ ]获取单个字符,这两种表示字符串的方式是不是就没有区别了呢?
    :有!它们最根本的区别是在内存中的存储区域不一样字符数组存储在全局数据区栈区,第二种形式的字符串存储在常量区。全局数据区和栈区的字符串(也包括其他数据)有读取和写入的权限,而常量区的字符串(也包括其他数据)只有读取权限,没有写入权限。

    三、C 语言指针数组(数组每个元素都是指针)

    一个数组中的所有元素保存的都是指针,那么我们就称它为指针数组
    此处一定要类比普通的指针使用方法

    int a = 16, b = 932, c = 100;
    
    //定义一个指针数组
    int *arr[3] = {&a, &b, &c};//也可以不指定长度,直接写作 int *parr[]
    
    //定义一个指向指针数组的指针
    int **parr = arr;
    
    printf("%d, %d, %d\n", *arr[0], *arr[1], *arr[2]);
    printf("%d, %d, %d\n", **(parr+0), **(parr+1), **(parr+2));
    
    运行结果:
    16, 932, 100
    16, 932, 100

           arr 是一个指针数组,它包含了 3 个元素,每个元素都是一个指针,在定义 arr 的同时,我们使用变量 a、 b、 c 的地址对它进行了初始化,这和普通数组是多么地类似。
           parr 是指向数组 arr 的指针,确切地说是指向 arr 第 0 个元素的指针,它的定义形式应该理解为 int *(*parr),括号中的*表示 parr 是一个指针,括号外面的 int *表示 parr 指向的数据的类型。 arr 第 0 个元素的类型为 int *,所以在定义 parr 时要加两个 *。
           第一个 printf() 语句中, arr[i] 表示获取第 i 个元素的值,该元素是一个指针,还需要在前面增加一个 * 才能取得它指向的数据,也即 *arr[i] 的形式。
           第二个 printf() 语句中, parr+i 表示第 i 个元素的地址, *(parr+i) 表示获取第 i 个元素的值(该元素是一个指针),**(parr+i) 表示获取第 i 个元素指向的数据。

    #include <stdio.h>
    int main(){
    char *str[3] = {
    "https://blog.csdn.net/qq_38351824/article/category/9343538",
    "百度搜索",
    "sumjess"
    };
    printf("%s\n%s\n%s\n", str[0], str[1], str[2]);
    return 0;
    }
    
    等价于
    
    #include <stdio.h>
    int main(){
    char *str0 = "https://blog.csdn.net/qq_38351824/article/category/9343538";
    char *str1 = "百度搜索";
    char *str2 = "sumjess";
    char *str[3] = {str0, str1, str2};
    printf("%s\n%s\n%s\n", str[0], str[1], str[2]);
    return 0;
    }
    
    

    需要注意的是,字符数组 str 中存放的是字符串的首地址不是字符串本身,字符串本身位于其他的内存区域, 和字符数组是分开的。
    也只有当指针数组中每个元素的类型都是 char *时,才能像上面那样给指针数组赋值,其他类型不行。

    四、二维数组指针(指向二维数组的指针)

    二维数组在概念上是二维的,有行和列,但在内存中所有的数组元素都是连续排列的,它们之间没有“缝隙”。以下面的二维数组 a 为例:

    int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };


    C 语言允许把一个二维数组分解成多个一维数组来处理。对于数组 a,它可以分解成三个一维数组,即 a[0]、 a[1]、a[2]。每一个一维数组又包含了 4 个元素,例如 a[0] 包含 a[0][0]、 a[0][1]、 a[0][2]、 a[0][3]。

    假设数组 a 中第 0 个元素的地址为 1000,那么每个一维数组的首地址如下图所示:

           为了更好的理解指针和二维数组的关系,我们先来定义一个指向 a 的指针变量 p:int (*p)[4] = a;括号中的*表明 p 是一个指针,它指向一个数组,数组的类型为 int [4],这正是 a 所包含的每个一维数组的类型。[ ]的优先级高于*, ( )是必须要加的,如果赤裸裸地写作 int *p[4],那么应该理解为 int *(p[4]), p 就成了一个指针数组,而不是二维数组指针。
           对指针进行加法(减法)运算时,它前进(后退)的步长与它指向的数据类型有关, p 指向的数据类型是 int [4],那么 p+1 就前进 4×4 = 16 个字节, p-1 就后退 16 个字节,这正好是数组 a 所包含的每个一维数组的长度。也就是说, p+1 会使得指针指向二维数组的下一行, p-1 会使得指针指向数组的上一行。
           数组名 a 在表达式中也会被转换为和 p 等价的指针!
           下面我们就来探索一下如何使用指针 p 来访问二维数组中的每个元素。按照上面的定义:

    1. p 指向数组 a 的开头,也即第 0 行; p+1 前进一行,指向第 1 行
    2. *(p+1)表示取地址上的数据,也就是整个第 1 行数据。注意是一行数据,是多个数据,不是第 1 行中的第 0 个。
    3. *(p+1)+1 表示第 1 行第 1 个元素的地址。如何理解呢?
      *(p+1)单独使用时表示的是第 1 行数据,放在表达式中会被转换为第 1 行数据的首地址,也就是第 1 行第 0 个
      元素的地址,因为使用整行数据没有实际的含义,编译器遇到这种情况都会转换为指向该行第 0 个元素的指针;
      就像一维数组的名字,在定义时或者和 sizeof、 & 一起使用时才表示整个数组,出现在表达式中就会被转换为指向数组第 0 个元素的指针。
    4. *(*(p+1)+1)表示第 1 行第 1 个元素的。很明显,增加一个 * 表示取地址上的数据。
      a+i == p+i
      a[i] == p[i] == *(a+i) == *(p+i)
      a[i][j] == p[i][j] == *(a[i]+j) == *(p[i]+j) == *(*(a+i)+j) == *(*(p+i)+j)
      
      【实例】使用指针遍历二维数组
      
      #include <stdio.h>
      int main(){
      int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
      int(*p)[4];
      int i,j;
      p=a;
      for(i=0; i<3; i++){
      for(j=0; j<4; j++) printf("%2d ",*(*(p+i)+j));
      printf("\n");
      }
      return 0;
      }
      
      运行结果:
      0 1 2 3
      4 5 6 7
      8 9 10 11

      下面是一个简单的例子

    五、指针数组和二维数组指针的区别:

    指针数组和二维数组指针在定义时非常相似,只是括号的位置不同:

    int *(p1[5]);    指针数组,可以去掉括号直接写作 int *p1[5];
    int (*p2)[5];    二维数组指针,不能去掉括号

           指针数组和二维数组指针有着本质上的区别:指针数组是一个数组,只是每个元素保存的都是指针,以上面的 p1为例,在 32 位环境下它占用 4×5 = 20 个字节的内存。二维数组指针是一个指针,它指向一个二维数组,以上面的 p2 为例,它占用 4 个字节的内存。

    六、常见指针变量的例子集合:

    常见指针变量的定义
    定 义含 义
    int *p;p 可以指向 int 类型的数据,也可以指向类似 int arr[n] 的数组。
    int **p;p 为二级指针,指向 int * 类型的数据。
    int *p[n];p 为指针数组。 [ ] 的优先级高于 *,所以应该理解为 int *(p[n]);
    int (*p)[n];p 为二维数组指针。
    int *p();p 是一个函数,它的返回值类型为 int *。
    int (*p)();p 是一个函数指针,指向原型为 int func() 的函数。

    ① 二级指针:指向一级指针的地址

    #include <stdio.h>
    int main(){
    
    int a[2] = {0,1};
    
    int *pt1 = &a[1];   // 将 a[1] 的地址赋值给pt1 
    
    int **pt = &pt1;    // 二级指针 将指针pt1的地址赋值给pt 
    
    printf("利用二级指针pt 获取pt1的指针地址 :%p\n",pt );
    printf("显示自己(指针pt1)的地址 :         %p\n",&pt1 );
    
    return 0;
    }

    ② 指针数组:[ ]优先级高于 *,所以应该理解为  int * ( p[n] );

    #include <stdio.h>
    int main(){
    
    int a[4] = {0,1,2,3};
    
    int *pt[4] = { a, &a[1], &a[2], &a[3]};
    
    printf("显示  %p\n",&pt );     //打印数组的首地址, 
    printf("显示  %p\n",&pt[0] );  //也是数组第一个元素的地址 
    
    printf("显示  %p \n",pt[2]);   //打印第三个元素的地址
    printf("显示  %p \n", &a[2]);  //验证第三个元素的地址 是否正确 
    
    printf("显示  %d \n", a[2]);    //打印数组第三个数据 
    printf("显示  %d \n",*pt[2]);   //验证pt[2]到底是不是表示第三个元素的地址
    printf("显示  %d \n", *&a[2]);  //再次验证第三个元素的地址 是否正确 
    
    return 0;
    }

    ③ 二维数组指针

    #include <stdio.h>
    int main()
    {
    int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
    
    int i = 1 ,j = 2;
    
    int(*p)[4];  //二维数组指针p 
    
    p=a;  //二维数组指针p 指向 数组a的首地址
    
    printf("第i行,第j个元素的地址是 : %p \n",   (*(p+i)+j) );  //第i行,第j个元素的地址 
    printf("第i行,第j个元素的数值是 : %d \n", * (*(p+i)+j) );  //第i行,第j个元素的数值
    
    printf("验证:\n");
    
    printf("第i行,第j个元素的地址是 : %p \n",   &a[1][2] );  //第i行,第j个元素的地址 
    printf("第i行,第j个元素的数值是 : %d \n",    a[1][2] );  //第i行,第j个元素的数值
    
    return 0;
    }

    ④ int *p();  函数返回值类型为  int *

    #include <stdio.h>
    
    int n = 100;
    
    int *test(void) //返回一个int *类型(地址) 
    {
     return &n;
    }
    
    int main()
    {
     int *p , n;
     
     p = test();  //指针p指向这个地址 
     n = *p;      //从这个地址获取值 
     
     printf("value = %d\n", n); //该地址的值是否为 100 
     
     return 0;
    }

    ⑤ 函数指针:int (*p)() ; 

    #include <stdio.h>
    
    int m = 99;
    
    int *test(int * a) //第一个*代表返回一个int *类型(返回一个地址) 
    {                  //第二个*传入一个地址
     return a;         //return 返回一个地址 
    }
    
    int main()
    {
     int *p ;         //定义一个指针变量 
     int *(*pt)(int *c) = test ;  //第一个*函数指针:int (*p)() ;第一个* 是要与 test 函数参数列表一致。  
                                  //第二个*函数指针:int (*p)() ;
                                  //第三个*函数指针:int (*p)() ;第二个括号中的int *c 是要与 test 函数参数列表一致。 
                                  //下面再对比解释下。                              
                                  //int *(*pt)(int *c)     对比看一下实际就是将*pt = test ;其他部分一致 
                                  //int * test(int * a)    而*pt = test 就是pt指向函数首地址 	
    							  					  
     p = (*pt)(&m);   //函数(*pt)(&m)返回一个地址,指针p指向这个地址 
    //---------------------------------------------------------------------------------------------------//
    //上面的内容其实就做了一个简单的事情,将指针p指向全局变量m的地址(即p=&m),转这么一圈使用来学习指针的//
    // 下面就来验证,我们之前做的是对。                          
    	
     printf("m的地址为          :%p\n",&m);//这是m的地址 
     printf("验证指针:m的地址为:%p\n",p); //这是经过风波的m的地址,用来验证我们之前的一通指针操作是否正确
      
     printf("m的value =          %d\n",m); //该地址的值是否为 99
     printf("验证指针:m的value= %d\n",*p); //这是经过风波的m的值,用来验证我们之前的一通指针操作是否正确 
     
     return 0;
    }

     

    展开全文
  • C语言指针指向数组的两种方法

    千次阅读 2020-03-23 22:55:16
    #include <stdio.h> int main() { int a[]={1,2,3};...//指针pa直接指向数组名 pb=&a[0];//指针pb指向数组a的第一元素的地址 printf("pa=%p\n",pa); printf("pb=%p",pb); return 0; } ...

    第一种方法:将指针指向数组名
    第二种方法:将指针指向数组的第一个元素的地址
    这两种方法都可以的原因是数组的第一个元素的地址就是数组的地址

    #include <stdio.h>
    int main()
    {
    	int a[]={1,2,3};
    	int *pa,*pb;//定义两个指针
    	pa=a;//指针pa直接指向数组名
    	pb=&a[0];//指针pb指向数组a的第一元素的地址
    	printf("pa=%p\n",pa);
    	printf("pb=%p",pb);
    	return 0;
    }
    
    展开全文
  • 主要介绍了C语言二维数组指针指向问题,文中不建议用二级指针来访问二维数组,需要的朋友可以参考下
  • 1.问文俊的题 2. 注意*和[]等价 注意行指针(类型(*指针变量名)[m];)和列指针(*p)的区分 m是列数 注意运行结果

    关于输入地址

    疑惑:既然这里的p1 p2代表ab的地址,就是系统随机的一串数字,为啥针对p1p2的输入,输入的就是内容值,而不是输入改变他的地址值
    解答:scanf需要传入的参数本来就是地址 如scanf("%d%d", &a, &b); 输入的东西会被我们传入的地址储存。
    指针是一个地址,而指针变量是存放地址的变量,注意区分
    在这里插入图片描述

    关于 *++p, ++*p的问题

    在这里插入图片描述
    在这里插入图片描述

    指向数组的指针

    1. 数组名是代表该数组的首地址
    2. 是个地址常量,不能再更改
    3. 所以数组名不能放在赋值号的左边,不能放在加加减减的前后,如a++,无法实现。
    4. 二维数组的数组名特点同一维数组一样,不同的是其数组名为行指针,数组名加一,会跳到下一行,并且不能用列指针变量与其赋值。
    5. [ ] 实际上是变址运算符,既将a[ i ]按照a+i计算地址,然后找出此地址单元中的值。
    6. 若指针变量p1 p2 都指向同一数组中的元素,执行p1-p2,得到两个元素之间间隔的元素。但是两个地址不能相加,它们的相加没有实际意义。

    以下情况,函数内形参的值改变,可以对实参造成影响:

    在这里插入图片描述

    指向多维数组的指针

    在这里插入图片描述

    !!注意在指向数组的指针中*和[]等价 ,既 * (a+i)和a[ i ]等价

    注意行指针(类型(*指针变量名)[m];)其中m是数组列数 和列指针(*p)的区分

    *列指针: int p ;
    *行指针: int (p)[m];

    在这里插入图片描述
    注意运行结果
    在这里插入图片描述

    数组指针和指针数组的区别

    数组指针(也称行指针)
    定义 int (*p)[n];
    ()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。

    如要将二维数组赋给一指针,应这样赋值:
    int a[3][4];
    int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。
    p=a; //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
    p++; //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]

    所以数组指针也称指向一维数组的指针,亦称行指针。

    指针数组
    定义 int p[n];
    []优先级高,先与p结合成为一个数组,再由int
    说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1是错误的,这样赋值也是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]…p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 p=a; 这里p表示指针数组第一个元素的值,a的首地址的值。
    如要将二维数组赋给一指针数组:
    int *p[3];
    int a[3][4];
    for(i=0;i<3;i++)
    p[i]=a[i];
    这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]
    所以要分别赋值。

    这样两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。
    还需要说明的一点就是,同时用来指向二维数组时,其引用和用数组名引用都是一样的。
    比如要表示数组中i行j列一个元素:
    (p[i]+j)、((p+i)+j)、((p+i))[j]、p[i][j]

    优先级:()>[]>*
    此段出处:数组指针和指针数组的区别

    展开全文
  • C语言指针数组详解

    千次阅读 多人点赞 2019-03-06 12:59:37
    1.指针数组的关系 当一个指针变量被初始化成数组名时,就说该指针变量指向数组。如: char str[20], *ptr; ptr=str; ptr 被置为数组 str 的第一个元素的地址,因为数组名就是该数组的首地址,...
  • 数组地址偏移与指向数组指针偏移的关系 引言: 在学习C语言过程中,使用数组的情况比较多,那么这里简单描述一下比较容易踩坑的数组地址的问题。 一、数组地址偏移与指向数组指针偏移 例如,定义一个数组,如下: ...
  • C语言指针数组指针作为参数

    千次阅读 2019-07-06 16:52:35
    //其实就是把形参数组也当成指针看待,是一个指向数组a的首地址的指针 int a[5]; //能引用的下标a[0] - a[4] a[0] = 85; a[1] = 70; a[2] = 98; a[3] = 92; a[4] = 78; printf("a[3]=%d,a[4]=%d\n",a[3...
  • C语言数组指针指向数组指针

    千次阅读 2017-05-19 01:23:43
    数组(Array)是一系列具有相同类型的数据的集合,每一份数据叫做一个数组元素(Element)。...定义数组时,要给出数组名和数组长度,数组名可以认为是一个指针,它指向数组的第 0 个元素。在C语言中,我们
  • 定义数组时,一定要给出数组名,数组名可以认为是一个指针,它指向数组的第 0 个元素。在C语言中,我们将第 0 个元素的地址称为数组的首地址。虽然可以认为是一个指针,但你在定义时千万别再数组变量名前面加 * ,否...
  • C语言二维数组指针指向二维数组指针)详解

    万次阅读 多人点赞 2020-05-27 17:43:22
    如有需要,请访问C语言二维数组指针指向二维数组指针)详解 二维数组在概念上是二维的,有行和列,但在内存中所有的数组元素都是连续排列的,它们之间没有“缝隙”。以下面的二维数组 a 为例: int a[3][4] = { ...
  • 了解过C语言的人,都会知道C语言有一种独特的变量,那就是指针指针是一把双刃剑,它为我们提供了操作内存的手段,但同时不恰当的使用,会为我们带来很多麻烦。如何理解指针呢?如果把一个个内存单元看做一个个房间...
  • 使用指针遍历数组 四.猜你喜欢 零基础 C/C++ 学习路线推荐 : C/C++ 学习目录 >> C 语言基础入门 一.使用数组下标遍历数组 数组中的每个元素都有一个序号,这个序号从 0 开始,称为下标 index,例如,a[0] ...
  • C语言 指针数组指向指针指针

    千次阅读 2019-05-22 16:44:29
    一个数组的元素值为指针则是指针数组指针数组是一组有序的指针的集合。 指针数 组的所有元素都必须是具有相同存储类型和指向相同数据类型的指针变量。 指针数组说明的一般形式为:类型说明符 *数组名[数组长度] ...
  • c语言指针数组和数组指针-解释和用法

    千次阅读 多人点赞 2019-06-15 19:51:21
    数组指针指针数组: 优先级:()>[]>* 首先我们要说的一个知识点是 int *p[3] 和 int (*p)[3]的区别 ...简单来说,就是int (*p)[3]是指一个指向数组指针,它其实还是一个指针,只不过是指向数组而已...
  • 详解C语言中的数组指针指针数组

    万次阅读 多人点赞 2018-05-06 21:52:39
    数组指针的意思即为通过指针引用数组,p先和*结合,说明了p是一个指针变量,指向一个大小为5的数组。所以,int (*p)[5]即为一个数组指针。int *p[5]则是一个大小为5且存放整型指针数组。 二、数组元素的指针 1....
  • ![图片说明](https://img-ask.csdn.net/upload/201805/08/1525778822_142150.png) !...!...!...!...想请教各位大佬这几个题中指针所代表的含义 如果能解释一下题目的解题过程就更好了 最近学指针 真的是被它搞得有点晕
  • c语言最常见的几种东西:结构体,数组指针和函数。单个定义很好理解,组合在一起就会让人头大。先说函数、数组指针的组合。 1、函数、数组指针的组合 包括指针函数、函数指针指针数组和数组指针,先从...
  • 指针做参数 #include &lt;stdio.h&gt; void swap(int *a, int* b) { int t = *a; *a = *b; *b = t; } int main() { int a = 3, b = 4; swap(&amp;a, &amp;b); printf("%d %d",...
  • C语言指针访问数组元素

    千次阅读 2019-06-14 11:05:11
    C语言当中数组的名称代表数组的首地址,如果取数组名称的地址,C语言认为就是取数组的首地址。 通过指针使用数组元素 通过指针计算,不是把指针当做一个整数,计算结果,而是指针在内存当中移动 p + 1代表&...
  • 主讲人周芸 教学目标 掌握一维数组指针的用法 理解一维数组指针的本质 具备应用一维数组指针编程的能力 张丽去排队打疫苗医生通过叫号的方式依次注射 引入 一指向一维数组指针 通过指针引用一维数组元素时需要...
  • C语言指向一维数组指针

    万次阅读 多人点赞 2018-04-17 11:41:53
    int array[5] = {1, 2, 3, 4, 5}; // 定义数组 ...上述三条语句分别定义了数组, 指向数组元素的指针指向数组指针. 内存情况如图示: 对于指向数组元素的指针很好理解, 但是怎样理解 指向数组指针...
  • 一、指针。 1、指针的概念:指针就是地址。 2、指针的大小是固定的(32位平台下是4字节,64位平台下是8字节) ...*p(对指针解引用),解引用是指针指向其对应的内容 字符指针: char ch='p';char*q
  • C语言指针访问数组元素

    千次阅读 2015-06-29 16:40:01
    数组元素都是连续存放的,...指针变量加减n时,代表将该指针的地址加减n*变量字节大小。 如果arr是数组,arr+1代表索引为1的元素地址,arr存放索引为0的元素地址, arr +1与 &arr[1]等价 如果arr是数组,*(arr+1)取
  • 由指针变量组成的数组——实际是一个指针——长度固定(32 位系统下占 4 个字节)——指针指向数组——指向的数组占多少个字节不确定 首先这个变量是一个数组 其次,”指针”修饰这个数组,意思是说这个数组的所有...
  • 这样让指针数组里的指针指向数组为什么不行,哪里错了吗(c语言指针数组),要怎么改

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 124,904
精华内容 49,961
关键字:

c语言指针指向数组

c语言 订阅