如何在c语言二维数组中使用指针

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在c语言二维数组中使用指针相关的知识,希望对你有一定的参考价值。

# include <stdio.h>#include<stdlib.h>int main()int i, j;int array[2][8] = 1,2,3,4,5,6,7,8 ,9,10,11,12,13,14,15,16 ;replace(int array);for (j = 0; j < 2; j++)printf("\n");for (i = 0; i < 8; i++)printf(" %4d ", array[j][i]);printf("\n");system("pause");return 0;int replace(int array[])int i, j;int t; for (j = 0; j < 2; j++) for (i = 0; i < 4; i++) t = array[j][i];array[j][i] = array[1 - j][7 - i];array[1 - j][7 - i] = t; 没有学指针,希望可以补充一下,完善代码。程序目的是让二维数组行和列进行倒序(即 1,2,3,4,56,7,8 9,10,11,12,13,14,15,16变为16,15,14,13,12,11,10,98,7,6,5,4,3,2,1)以下是错误

程序中有些问题:
1、函数的定义有错误(参数格式不对);
2、程序中没有调用函数(或者说是调用格式有误)
3、函数中的处理逻辑需要修改(一步一步来,这样容易处理和理解)。
你定义的函数是使用数组作为参数的,数组名本身就是个地址(相当于指针)。
下面在手机上用易历知食软件里的微C程序设计来演示修正后的代码并运行程序,供参考。
手机上修正后的代码如下图:
手机上运行的效果如下图所示:

参考技术A 对于a[i][j](二维数组的大小为n×m)而言,
首先要搞清楚行指针和列指针
行指针:&a[i]或者a+i指向行,&a[i]=&*(a+i)=a+i
列指针:a[i]或*(a+i)指向列,a[i]等价于*(a+i)
元素的引用方式有如下三种方式
1.通过地址引用二维元素
*(&a[i][j]),
*(a[i]+j),
*(*(a+i)+j),
*(a[0]+m*i+j)
*(&a[0][0]+m*i+j)
(*(a+i))[j]
2.建立一个指针数组引用二维元素
int *p[3],a[3][2],i,j;
for(i=0;i<3;i++)
p[i]=a[i];//p[i]用来存放地址,a[i]为列地址
等价如下
(1) *(p[i]+j) 与*(a[i]+j)对应
(2)*(*(p+i)+j) 与*(*(a+i)+j)对应
(3)(*(p+i))[j] *(p[i]+j) 与*(a[i]+j)对应
(4)p[i][j] 与a[i][j]对应
3.建立一个行指针引用二维数组元素
int a[3][2],(*p)[2];
p=a;
(1) *(p[i]+j) 与*(a[i]+j)对应
(2)*(*(p+i)+j) 与*(*(a+i)+j)对应
(3)(*(p+i))[j] 与(*(a+i))[j]对应
(4)p[i][j] 与a[i][j]对应
例题如下
1.
#include<stdio.h>
main()

int score[][4]=60,70,80,90,56,89,67,88,34,78,90,66;
int i,j;
printf("输入学生号:0-2");
scanf("%d",&i);
printf("the score of No.%d are:\n",i);
for(j=0;j<4;j++)
printf("%d\t",*(*(score+i)+j));//score+i为列指针,*(score+i)为行指针
printf("\n");

2.
#include<stdio.h>
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++)//使p依次指向下一个元素,a[i]和*(a+i)是指向列的指针;&a[i]或a+i是指向行的指针

if((p-a[0])%4==0)printf("\n");
printf("%4d",*p);//输出p指向的数组元素的值

printf("\n");

3
#include<stdio.h>
main()

int score[][4]=60,70,80,90,56,89,67,88,34,78,90,66;
int i,j;
printf("输入学生号:0-2");
scanf("%d",&i);
printf("the score of No.%d are:\n",i);
for(j=0;j<4;j++)
printf("%d\t",*(score[i]+j));
printf("\n");

4
#include<stdio.h>
main()

int score[][4]=60,70,80,90,56,89,67,88,34,78,90,66;
int i,j,*p;
printf("输入学生号:");
scanf("%d",&i);
printf("the score of No.%d are:\n",i);
for(p=score[i];p<score[i]+4;p++)
printf("%d\t",*p);//p+i指向第i行,*(p+i)指向第i行0列元素*(p+i)+j指向第i行j列元素,是列地址
printf("\n");

5.
#include<stdio.h>
main()

int score[][4]=60,70,80,90,56,89,67,88,34,78,90,66;
int i,j,*p;
printf("输入学生号:");
scanf("%d",&i);
printf("the score of No.%d are:\n",i);
for(p=score[i],j=0;j<4;j++)
printf("%d\t",*(p+j));
printf("\n");

6
#include<stdio.h>
main()

int score[][4]=60,70,80,90,56,89,67,88,34,78,90,66;
int i,j,(*p)[4];//指针变量p指向包括4个整型元素的一维数组;
p=score;//p指向二维数组0行元素,p+1所指向的元素是p所指向元素的下一行元素;
printf("输入学生号:0-2");
scanf("%d",&i);
printf("the score of No.%d are:\n",i);
for(j=0;j<4;j++)
printf("%d\t",*(*(p+i)+j));//p+i指向第i行,p是行指针,*(p+i)指向第i行0列元素,是列指针。*(p+i)+j指向第i行j列元素,是一个元素的地址
printf("\n");
参考技术B 正如楼下所言 int **p ,定义的p是一个指向int*型的指针
int (*p)[10]是一个指向数组的指针 数组长度为10
假如定义成 deal(int **p),传参数时要加强制类型转换: deal((int**)a);
并且使用p时不能用下标,p[2][3]是错误的,因为不知道p指向的int*型的长度,无法编译成*(p+2*10+3)
必须自己写成*(p+2*10+3)来调用
假如定义成 deal(int (*p)[10])就不一样了,编译器就能知道p是一个指向长度为10的数组的指针
那么p[2][3]就能编译成*(p+2*10+3)了
总之,C语言是很灵活的,不同的定义方式配上不同的用法,都是能得到正确的结果的
不知道这么说楼主明白了没?
同样的还有多维数组对多维指针的问题,楼主可以自己类推一下

C语言进阶4——指针的进阶

指针的进阶(1)


前言

本文开始学习指针进阶相关的知识点了。前面已经在初识C语言、C语言基础阶段学习过了指针的内容了:

在基础阶段初步知道了指针的概念:

  • 指针就是个变量,用来存放地址,地址唯一标识一块内存空间
  • 指针的大小是固定的4/8个字节(32位平台/64位平台)
  • 指针是有类型,指针的类型决定了指针的±整数的步长,指针解引用操作的时候的权限
  • 指针的运算

在进阶阶段将会按照下面顺序,更加深入地依次学习指针的相关内容:

  • 字符指针
  • 数组指针
  • 指针数组
  • 数组传参和指针传参
  • 函数指针
  • 函数指针数组
  • 指向函数指针数组的指针
  • 回调函数
  • 指针和数组面试题的解析

1、字符指针

指针类型为字符指针 char*

int main()

	char ch = 'w';
	char *pc = &ch;//字符指针
	*pc = 'a';
	printf("%c\\n", ch);
	
	代码是将字符串的abcdef的首字符的地址存放指针pa里了
	用const限制指针pa,即常量指针:
	指针指向的地址里存放的内容,*pa 不能修改, 
	指针指向的地址,pa,可以修改
	const char* pa = "abcdef";
	//*pa = 'a';//错误的,const限制后,不能修改
	printf("%c\\n", *pa);
	printf("%s\\n", *pa);

	return 0;

通过调试看到常量字符串是将其首字符 ‘a’ 的地址赋值给指针 *pa :

int main()

	char ch1[] = "hello world";//字符串一般用数组定义
	char ch2[] = "hello world";
	const char* p1 = "hello world";//指针变量接受字符串地址
	const char* p2 = "hello world";

	if (ch1 == ch2)
	
		printf("ch1 and ch2 are same\\n");
	
	else
	
		printf("ch1 and ch2 are not same\\n");
	
	if (p1 == p2)
	
		printf("p1 and p2 are same\\n");
	
	else
	
		printf("p1 and p2 are not same\\n");
	
	return 0;

  • 这里p1和p2指向的是同一个常量字符串
  • C/C++会把常量字符串存储到单独的内存中的常量区域
  • 当几个指针指向同一个字符串的时候,他们实际会指向同一块内存
  • 用相同的常量字符串,去初始化不同的数组的时候就会开辟出不同的内存块,ch1和ch2不同

2、指针数组

指针数组:指针数组就是一个数组,数组里每个元素都是指针,即是地址

前面关于数组,我们学过了几种类型的数组:

整型数组
int arr[10];存放整型的数组,数组里的每个元素都是int类型

字符数组
char arr2[10];存放字符的数组,数组里的每个元素都是char类型

指针数组
int* arr[10];存放指针的数组,数组里的每个元素都是int*类型,即指针,也是地址

2.1 在一维数组中使用

int main()

	int a = 10;
	int b = 20;
	int c = 30;
	int* p1 = &a;
	int* p2 = &b;
	int* p3 = &c;

	int* arr[3] =  &a,&b,&c ;//指针数组,数组的元素都是地址,也就是指针
	for (int i = 0; i < 3; i++)
	//arr[i]每个元数都是地址,对地址解引用就是取a、b、c的值
		printf("%d ", *(arr[i]));
	
	return 0;

调试结果见下图:

2.2 在二维数组中使用

int main()

	int arr1[5] =  1,2,3,4,5 ;
	int arr2[5] =  2,3,4,5,6 ;
	int arr3[5] =  3,4,5,6,7 ;

	int* parr[3] =  arr1,arr2,arr3 ;//指针数组,数组元素都是地址

	for (int i = 0; i < 3; i++)
	
		for (int j = 0; j < 5; j++)
		
			printf("%d ", parr[i][j]);//parr[0]=arr1
		
		printf("\\n");
	
	printf("\\n");
	for (int i = 0; i < 3; i++)
	
		for (int j = 0; j < 5; j++)
			
			printf("%d ", *(parr[i] + j));	//
		
		printf("\\n");
	
	printf("\\n");
	for (int i = 0; i < 3; i++)
	
		for (int j = 0; j < 5; j++)
		
			printf("%d ", *(*(parr + i) + j));//*(parr + i) = parr[i]
		
		printf("\\n");
	
	return 0;

)

调试结果见下图:

3、数组指针

3.1 数组指针的定义

数组指针是指针,这个指针指向数组,即指针存放数组的地址:

前面关于指针,我们学过了几种类型的指针:

整形指针: 
int* pint; 指向整形数据的指针,本身类型是int*,指针指向的地址里存放的数据类型是int

浮点型指针: 
float* pf; 指向浮点型数据的指针,本身类型是float*,指针指向的地址里存放的数据类型是float

数组指针:
int (*p)[10];指向数组的指针,本身的类型是int(*)[10], 指针存放了数组的地址,这个数组有10个元素,每个元素的数据类型是int

所以p是一个指针,指向一个数组,叫数组指针。要注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合

//数组指针
int main() 

	char* ch;//指向字符型数据的指针
	int* a;//指向整形数据的指针
	float* pf;//指向浮点型数据的指针
	int(*pa)[10];//数组指针,是一个指针,指向数组的指针,指向的数组有10个元素,每个元素的类型是int整形
	
	int* p1[10];//指针数组,是一个数组,数组里的每个元素都是指针变量,就是地址

3.2 &数组名和数组名的区别

代码如下(示例):

int main()

	int a = 10;
	int* p = &a;
	int arr[10] =  0 ;
	printf("%p\\n", arr);
	printf("%p\\n", arr + 1);
	printf("%p\\n", &arr[0]);
	printf("%p\\n", &arr[0] + 1);
	printf("%p\\n", &arr);
	printf("%p\\n", &arr+1);
	return 0;

这部分内容在基础阶段已经学习过,【C语言基础5——数组(1)】4.2 数组名是什么?

  • arr是数组名,即是首元素地址,数值与&arr[0]、&arr相同
  • &arr[0]是首元素地址
  • &arr是整个数组的地址
  • arr+1,地址移动到第二个int元素,移动4个字节
  • &arr[0]+1,地址移动到第二个int元素,移动4个字节
  • &arr+1.地址移动了一个数组的长度,移动了40个字节


由上面分析可知,&arr 的类型是: int(*)[10] ,是数组指针类型。

3.3 数组指针的使用

数组指针指向的是数组,那数组指针中存放的应该是数组的地址

int main()

	int arr[10] = 1,2,3,4,5,6,7,8,9,0;
	int (*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量p
	//但是我们一般很少这样写代码
	return 0;

3.3.1 在一维数组中使用

//形参使用数组
void print1(int arr[], int sz)//传参接收的是首元素的地址,没学指针前,写成数组形式好理解

	for (int i = 0; i < sz; i++)
	
		printf("%d ", arr[i]);
	
	printf("\\n");

//形参使用指针
void print2(int* p, int sz)//传参接收的是首元素的地址

	for (int i = 0; i < sz; i++)
	
		printf("%d ", *(p + i));//对地址解引用
	
	printf("\\n");

//形参使用数组指针,一维数组不这样用,繁琐了
void print3(int(*p)[10], int sz)

	for (int i = 0; i < sz; i++)
	//p是数组指针变量,存放的数组地址,*p解引用取得数组名arr,
	//数组名就是首元素的地址,*p=arr=&arr[0]
		printf("%d ", *(*p+i));//对地址解引用,*(arr+i)
	
	printf("\\n");


int main()

	int arr[10] =  1,2,3,4,5,6,7,8,9,10 ;
	int(*p)[10] = &arr;//指向数组的指针,将数组的地址赋值给指针变量p
	int sz = sizeof(arr) / sizeof(arr[0]);
	print1(arr,sz);
	print2(arr, sz);
	print3(&arr,sz);//一般一维数组不这样用,绕圈子了
	
	return 0;

上面三种函数的写法,结果相同,常用的是前两种,见下图:

3.3.2 在二维数组中使用

//形参使用二维数组,最常用的数组的写法
void print1(int arr[3][5],int a,int b)

	for (int i = 0; i < a; i++)
	
		for (int j = 0; j < b; j++)
		
			printf("%d ", arr[i][j]);
		
		printf("\\n");
	
	printf("\\n");

//形参使用数组指针,常用的写法, 第一行一维数组的地址用数组指针接收
void print2(int(*p)[5] , int a, int b)

	for (int i = 0; i < a; i++)
	
		for (int j = 0; j < b; j++)
		
			printf("%d ", p[i][j]);
			下面的方法也行,要复习二维数组,在二维数组中
			p+i是指向第i行的,是通过地址找到第i行,&arr[i]
			二维数组第i行,代表的是第i行的数组,即一个一维数组
			*(p+i)解引用地址,相当于拿到了第i行,即arr[i],也相当于第i行的数组名
			数组名表示首元素的地址,*(p+i) 就是第i行数组中的第一个元素的地址
			*(p + i) + j是通过地址找到第i行数组中第j个元素
			*(*(p + i) + j)解引用地址,拿到arr[i][j]这个元素的值
			//printf("%d ", *(*(p + i) + j));
		
		printf("\\n");
	
	printf("\\n");

//形参使用数组指针,传入什么参数,形参就怎么定义
void print3(int(*p)[3][5], int a, int b)

	for (int i = 0; i < a; i++)
	
		for (int j = 0; j < b; j++)
		
			printf("%d ", (*p)[i][j]);
		
		printf("\\n");
	
	printf("\\n");


int main()

	int arr[3][5] =  1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 ;
	int (*p)[3][5] = &arr;//一般很少这样使用
	print1(arr, 3, 5);
	print2(arr, 3, 5);//传参为数组首元素地址,即第一行数组的地址
	print3(&arr, 3, 5);//一般不会这样用
	return 0;

调试结果见下图:


总结

本文主要学习了关于指针进阶内容的前三个知识点:

  • 字符指针
  • 数组指针
  • 指针数组

下一篇继续学习指针进阶内容的其他知识点。

以上是关于如何在c语言二维数组中使用指针的主要内容,如果未能解决你的问题,请参考以下文章

C语言如何定义指针指向字符型二维数组

C语言指向二维数组的指针

C语言 如何定义一个二维指针数组?

c语言如何表示二维数组里面有#

C语言中二维数组行指针是啥

C语言二维数组问题