指针和数组(操作详解)

指针和数组

本文基本为深入理解指针的笔记

数组概述

不要混淆二维数组指针数组,它们类似但是行为会有差异

一维数组

  int vector[5] = { 1,2,3,4,5 };
  • 数组索引从0开始,到声明长度减一结束
  • 无效的索引访问数组会造成不可预期的行为
  printf("%d", sizeof(vector) / sizeof(int));
  • 数组长度除以元素长度获取元素的数量(不一定等于初始化的数量)

二维数组

我们可以将二维数组当作数组的数组,如果只用一个下标访问数组,得到的就是对应行的指针

int matrix[2][3] = { {1,2,3},{4,5,6} };
	for (int i = 0; i < 2; i++) {
		for (int j = 0; j < 3; j++) {
			printf("%d ", matrix[i][j]);
		}
	}
1 2 3 4 5 6

指针表示法和数组

单独使用数组名会返回数组地址,我们可以把数组地址赋给指针

  int vector[5] = { 1,2,3,4,5 };
  int* pv = vector;

注意:pv变量是指向数组的第一个元素而不是指向数组本身的指针

我们也可以使用&取数组的地址,不同于上面的表示法,这么做返回的是整个数组的指针

  printf("%p\n", vector);
  printf("%p\n", &vector);
  0000000EB10FF628
  0000000EB10FF628

我们可以验证一下,两个指针的区别,指向数组的第一个元素和指向整个数组的指针是不一样的

	int* pv = vector;
	int* pv = &vector;//报错:类型不一致  int (*) = int (*)[5]

正确做法

  int(*pv)[5] = &vector;

我们可以把数组下标用在指针上,pv[i]等价于*(pv+i)

for (int i = 0; i < 5; i++) {
		printf("%d ", *(pv + i));
	}
1 2 3 4 5

注意区分下面两种的指针表示法,第二种指针的值改变,不再指向数组的首元素

//第一种
	for (int i = 0; i < 5; i++) {
		printf("%d ", *(pv + i));
	}
	printf("&vector = %p", vector);
	printf(" pv = %p\n", pv);
	//第二种
	for (int i = 0; i < 5; i++) {
		printf("%d ", *pv);
		pv++;
	}
	printf("&vector = %p", vector);
	printf(" pv = %p\n", pv);
1 2 3 4 5 &vector = 000000B18CF0F5A8 pv = 000000B18CF0F5A8
1 2 3 4 5 &vector = 000000B18CF0F5A8 pv = 000000B18CF0F5BC

数组和指针的差别

vector[i]表示法生成的机器码从位置vector开始,移动i个位置,取出内容。而*(vector+i)表示法生成的机器码从位置vector开始,在地址上增加i,然后取出这个地址中的内容,尽管结果是一样的,生成的机器码却不一样。

用sizeof操作符对数组和同一个数组的指针操作也是不同的

	printf("sizeof(int *ptr) = %d\n", sizeof(int *)); 
	printf("sizeof(pv) = %d\n", sizeof(pv));
	printf("sizeof(vector) = %d\n", sizeof(vector));
  sizeof(int *ptr) = 8
  sizeof(pv) = 8
  sizeof(vector) = 20

用malloc创建一维数组

int* pv = (int*)malloc(5 * sizeof(int));
	for (int i = 0; i < 5; i++) {
		*(pv + i) = i+1;
	}

用realloc调整数组长度

实现getline函数

char* (getLine)(void) {
	const size_t sizeIncrement = 10;//缓冲区创建时的带线啊哦
	char* buffer = (char *)malloc(sizeIncrement);
	char* currentPosition = buffer;//指向缓冲区下一个空白位置的指针
	size_t maximumLength = sizeIncrement;//可以安全存入缓冲区的最大字符数
	size_t length = 0;//读入的字符数
	int character;//上次读入的字符数

	if (currentPosition == NULL) { return NULL; }//如果malloc函数分配失败,返回NULL

	while (1) {
		character = fgetc(stdin);//读字符
		if (character == '\n') break;//回车符 退出
		if (++length >= maximumLength) {//读入的字符数字超过安全存入的数
			char* newBuffer = (char *)realloc(buffer, maximumLength += sizeIncrement);//重新分配内存并返回指针,分配成功会释放原来的指针

			if (newBuffer == NULL) {//如果重新分配失败 返回NULL
				free(buffer);//释放之前buffer
				return NULL;
			}
			currentPosition = newBuffer + (currentPosition - buffer);//指向下一个字符位置的指针相应的去新的空间按之前的顺序指向
			buffer = newBuffer;
		}
		*currentPosition++ = character;//字符指针偏移并被赋值
	}
	*currentPosition = '\0';//跳出,赋值'\0'
	return buffer;//返回指向分配好的空间的指针
}
I am a student and I am a boy!
I am a student and I am a boy!

传递一维数组

将一维数组作为参数传递给函数实际时通过值类传递数组的地址。这样子传递更高效,因为不用拷贝传递整个数组而只是传递地址,不需在栈上分配内存。一般还要传递数组的长度,避免超出索引。

数组表示法

  void displayArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
      printf("%d ", arr[i]);
    }
    printf("\n");
  }
    int vector[5] = { 1,2,3,4,5 };
  	displayArray(vector, 5);

指针表示法

void displayArray(int *arr, int size) {
	for (int i = 0; i < size; i++) {
		printf("%d ", arr[i]);//数组表示法
		printf("%d ", *(arr+i));//指针表示法
	}
	printf("\n");
}

使用指针的一维数组

声明一个整数指针的数组

	int* arr[5];//每个元素都是指针
	for (int i = 0; i < 5; i++) {
		arr[i] = (int*)malloc(5 * sizeof(int));//为每个元素分配空间
		*arr[i] = i;
	}

arr[i]返回的是一个地址,通过*解引用得到的,*arr[i]才是一个整数


使用指针表示法

*(arr + i) = (int*)malloc(5 * sizeof(int));
**(arr + i) = i;

(arr+i)表示第i个元素的地址

*(arr+i)为修改元素中的内容,我们使用了*,于是修改了指针的值,完成了动态的内存分配

**(arr+i)是再对指针进行解引用,得到储存的int数据

如何解释arr[0][0] = 0

我们假设arr的每个元素都指向一个有5个元素的指针,则arr[0][0]代表arr第一个元素指向的第一个元素

指针和多维数组

int matrix[2][5] = { {1,2,3,4,5},{6,7,8,9,10} };
int(*pmatrix)[5] = matrix;//声明了一个数组指针

(*pmatrix)声明了一个数组指针,整条声明语句将pmatrix定义为一个指向二维数组的指针,每列5个元素

如果把括号删去就表示声明了5个元素的数组,数组类型是整数指针

  int(*pmatrix)[5] = matrix;
	printf("the address: %p\n", pmatrix[0]);
	printf("the address: %p\n", pmatrix[1]);
  the address: 0000002A6FD4F698
  the address: 0000002A6FD4F6AC

可以看到,地址差20,符合差一行元素的状况

传递多维数组

正确方式

	void display2DArray(int arr[][5], int rows);
	void display2DArray(int(*arr)[5], int rows);

错误错误:计算机会认为传入一维数组数组,里面都是整数指针

  void display2DArray(int *arr[5], int rows);

动态分配二维数组

分配可能不连续的内存

	int rows = 2, columns = 5;
	int** matrix = (int**)malloc(rows * sizeof(int*));
	for (int i = 0; i < rows; i++) {
		matrix[i] = (int*)malloc(columns * sizeof(int);
	}

分配连续内存

	int rows = 2, columns = 5;
	int** matrix = (int**)malloc(rows * sizeof(int*));
	matrix[0] = (int*)malloc(rows * columns * sizeof(int));
	for (int i = 1; i < rows; i++) {
		matrix[i] = matrix[0] + i * columns;
	}

  • 第一个malloc分配一个整数指针的数组,一个元素储存一行的指针
  • 第二个malloc分配所有所需的内存
  • 接下来利用一个for循环给每一个指针元素分配一部分内存
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值