C语言中指针及其应用高级篇(用指针实现数组的扩增)

本文详细介绍了C/C++中指针的使用,包括一级指针与一维数组的关系,以及如何通过malloc和calloc动态分配内存。讨论了指针作为变量的两种初始化方式,malloc在内存管理中的应用,特别强调了使用malloc创建一维数组和二维数组的方法。同时,对比了calloc和malloc在内存初始化上的差异,以及realloc在内存不足时如何重新分配内存并复制原有内容。

一、一级指针与一维数组

把指针充当变量的用法,在C/C++的数据结构学习中广为应用,这种用法学习起来是比较简单的。
先看代码。这里的代码,有string.h头文件包含的函数,和scanf,这两者在正常的写法中不用加“_s”,这篇随笔所及代码的运行环境是Visual Studio2017,编译器会把scanf等函数增强,因此为了正常运行,会加上“_s”.

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
int main() {

	//把指针充当变量的方式有两种
	//1. 通过变量的地址初始化
	int num = 1;
	int *pInt = &num;
	*pInt = 101;	//这里的*pInt等效于num
	printf("*pInt=%d\tnum=%d\n", *pInt, num);

	//2.1. 通过使用malloc初始化内存,让指针变成普通变量
	int *p = (int *)malloc(sizeof(int));
	if (p == NULL) {
		return 0;
	}
	*p = 101;
	printf("*p=%d\n", *p);
	free(p);
	p = NULL;

	//2.2 可以把指针变成数组,一级指针则成为一维数组 
	int *array = (int *)malloc(sizeof(int ) * 3);
	if (array == NULL) {
		return 0;
	}
	for (int i = 0; i < 3; i++) {
		scanf_s("%d", array + i);	//把从键盘输入的字符存储到数组中
		//array[i] = i;   自动添加数字元素到数组中
		printf("arr[%d]=%d,arr[%d]=%d\n", i, array[i], i, *(array + i));
	}
	free(array);
	array = NULL;

	//3. 指针作为字符数组
	char *pChar = (char *)malloc(sizeof(char) * 27);
	for (int i = 0; i < 26; i++)
	{
		pChar[i] = 'A' + i;
		printf("%c\t", pChar[i]);
	}
	printf("\n");
	
	//3.1 字符数组,字符串的区别
	pChar[26] = '\0';
	printf("%s\n", pChar);
	printf("\n");
	free(pChar);
	pChar = NULL;

	//3.2 关于字符数组赋值的问题,C语言中没有string类型
	char *pStr = (char *)malloc(sizeof(char) * 10);   //pStr[10];
	/*
		字符串的赋值只能通过两种方式
		1. 字符串采用字符的方式去处理
		2. 通过字符串拷贝函数去赋值
	*/
	strcpy(pStr, "Loveyou");
	printf("%s\n", pStr);
	free(pStr);
	pStr = NULL;
	
	//3.3 申请的数组长度可以为一个变量
	printf("你想输入多少个学生信息:");
	int count = 0;
	scanf_s("%d", &count);
	float *pScore = (float *)malloc(sizeof(float)*count);
	printf("请输入%d个学生成绩\n", count);
	for (int i = 0; i < count; i++)
	{
		scanf("%f", pScore + i);
	}
	for (int i = 0; i < count; i++)
	{
		printf("%f\t", pScore[i]);
	}
	printf("\n");
	free(pScore);
	pScore = NULL;
	system("pause");
	return 0;
}

把指针充当变量的用法有两种:
①:通过变量的得地址初始化;
②通过使用malloc初始化内存,让指针变成普通变量。

1.1通过变量的地址初始化

如代码中1.1的例子所写,定义一个普通变量并初始化,然后定义一个指针变量,通过取地址符号取到普通变量num的值,赋值给指针,此时指针变量 *pInt等效于变量num,在后面修改num的值的时候可以直接用指针变量来修改。这部分其实没什么好讲的,很简单。

2.1使用malloc函数使指针变量变成普通变量

申请一个存储int类型变量的内存,写法大概的如下:

int *p = (int *)malloc(sizeof(int));

格式: *基本数据类型 指针变量名 = (强制转换类型)malloc(sizeof(基本数据类型))
注意两点:
① 在正式编程中我们要用防御式编程的思想;
②在申请且使用了内存后,要及时释放内存,释放步骤为

  free(指针变量名字);
  指针变量名=NULL;
2.2使用 malloc申请一段内存

方式大概如下:

int *array = (int *)malloc(sizeof(int ) * 3);

格式: *基本数据类型 指针变量名 = (强制转换类型)malloc(sizeof(基本数据类型)需要申请的长度)
在例子2.2中,再复习一遍之前学过的内容,用array[i]和
(array+i)两种方式分别遍历一遍整形数组。

2.3 使用malloc申请字符类型的内存

方式大概如下:

char *pChar = (char *)malloc(sizeof(char) * 27);

我们用26个字母作为字符数组遍历。
这里需要注意的是:
①C语言中,字符数组是按照字符串来处理的;
②字符串的末尾,需要在字符串最后一位加上"\0"来结尾;
③字符数组和字符串是有区别的,因此用 %c而不是%s
④申请字符类型空时,代码中的27可以用变量替换掉。如替换成count。
第二条,我们可以把循环遍历中的

printf("%c\t", pChar[i]);
pChar[26] = '\0';

这两行代码用注释掉和不注释两种情况来比较,得出结论,如下两张图。
注释掉后的结果:
在这里插入图片描述
不注释的结果:
在这里插入图片描述
明显的,在注释掉循环中的打印代码后,通过比较有无字符串结尾处理得出结论。
第四条的写法,如上面代码所示,这一部分没有需要注意的东西,不做阐述。

二、二级指针与二维数组

这里说明,二级指针并不能直接转成二维数组,二维数组中的元素都是普通变量,而二级指针指向的地址,存储的是一级指针变量的地址。
附上一张图
在这里插入图片描述

这部分的讲解基本都在代码块的注释里,复制到文本文件里食用口味更加。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//1.2  通过返回值申请内存,这是一个申请数组的函数
int *Mallo_Array(int arrLength) {
	int *array = (int *)malloc(sizeof(int *)*arrLength);
	return array;	//返回数组首地址
}
//1.3  通过参数申请内存
void  malloc_Array1D(int **array, int arrLen) {
	//通过一级指针修改普通变量的值,因此改变普通变量时候传递一级指针
	//通过二级指针修改一级指针的指针变量,因此改变指针指向的时候要传递二级指针
	*array = (int *)malloc(sizeof(int  *)*arrLen);
}

//1.4  字符串当做函数参数,申请内存
//通过外部变量来初始化字符串,如申请一个内存存储字符串,可能传一个常量,而常量是不能修改的,因此要申请一段内存来保存常量
//这里不用malloc而是用 strlen,因为fileName只是一个指针,用malloc申请到的永远是4个字节
void malloc_String(const char *fileName) {
	char *pStr = (char *)malloc(strlen(fileName) + 1);		//计算长度,此处字符串数组长度要+1
	strcpy(pStr,fileName);		//使用strcpy来赋值,把fileName拷贝到pStr中就可以对fileName进行修改操作
	printf("%s", pStr);
}


int main() {
	//1.1 二级指针和二维数组
	int *pInt = (int *)malloc(sizeof(int) * 3);		//意味着每一个SecPointer[i]都是一个一级指针
	int **SecPointer = (int **)malloc(sizeof(int *) * 9);	//开辟九个长度的存放一级指针变量的数组
	for (int i = 0; i < 9; i++) {
		SecPointer[i] = (int *)malloc(sizeof(int) * 9);		//为九个指针申请内存使其成为二维数组
	}
	SecPointer[7][7] = 101;
	printf("%d\n", SecPointer[7][7]);
	free(SecPointer);
	SecPointer = NULL;

	//1.2  调用函数申请一个容量为3的一维数组
	int *array = Mallo_Array(3);
	for (int i = 0; i < 3; i++) {
		array[i] = i;
		printf("array[%d]=%d,array[%d]=%d\n", i, *(array+i),i,array[i]);
	}
	free(array);
	array = NULL;

	//1.4
	malloc_String("LoveYou");
	printf("\n");
	system("pause");
	return 0;
}

下面是运行结果。
在这里插入图片描述

三、malloc,realloc,calloc

上代码。

#include<stdio.h>
#include<stdlib.h>

//1.1  calloc函数在申请内存后会默认初始化 
//1.2  realloc函数可在内存不足的情况下重新申请内存,且具有复制功能,即会把原来内存里的元素再复制到新申请的内存中

int main() {
	//1.1
	int *pCalloc = (int *)calloc(3, sizeof(int));
	int *pMalloc = (int *)malloc(sizeof(int) * 3);
	for (int i = 0; i < 3; i++) {
		printf("Calloc[%d]=%d\n", i, pCalloc[i]);
	}
	printf("\n");
	free(pCalloc);
	pCalloc = NULL;
	for (int j = 0; j < 3; j++) {
		printf("Malloc[%d]=%d\n", j, pMalloc[j]);
	}
	printf("\n");
	free(pMalloc);
	pMalloc = NULL;

	//1.2
	int *pMall = (int *)malloc(sizeof(int) * 3);
	for (int x = 0; x < 3; x++) {
		pMall[x] = x;
	}
	realloc(pMall, sizeof(int) * 6);
	for (int y = 3; y < 6; y++) {
		pMall[y] = y;
	}
	for (int z = 0; z < 6; z++) {
		printf("%d", pMall[z]);
	}
	system("pause");
	return 0;
}

需要注意的是realloc,calloc,malloc在写法上的不同 ,三者分别两两放在一起比较:

int *pCalloc = (int *)calloc(3, sizeof(int));
int *pMalloc = (int *)malloc(sizeof(int) * 3);
int *pMall = (int *)malloc(sizeof(int) * 3);
realloc(pMall, sizeof(int) * 6);

可以看到calloc函数和malloc在申请内存时候的写法,只在后面部分的顺序不同;而realloc和malloc相比,则有很大的不同,这是因为他们的功能上有很大的差别:
①malloc:申请内存,不进行初始化;
②calloc:申请内存,并进行初始化,初始化为0;
③realloc:当之前申请的内存不足时候,重新申请内存,且申请的内存应为原来内存的整数倍。realloc在申请内存后,会把原内存的内容复制到新内存中。
下面是运行结果。
在这里插入图片描述

显而可见,calloc会自动将数组中的内容初始化为0,而malloc不会。在实际应用中,malloc的应用会比calloc多得多。而realloc通过使用前和使用后两种情况,将其打印输出,也可以很清晰的了解其功能。
为了更加清楚地明白realloc的运行机制,画图。
在这里插入图片描述
暂时到这里。
**

球球了,给点个赞吧 !(>-<)!

**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值