概述:
- 本文主要介绍了C语言中的一维动态数组和二维动态数组的使用方式。
- 核心的库“stdlib.h”,核心的库函数“malloc()”。
- 代码量较多,文字叙述较少,但绝对通俗易懂。
Table of Contents
一维动态数组
“传统数组”就是前面所使用的数组,与动态内存分配相比,传统数组主要有以下几个缺点:
1) 数组的长度必须事先指定,而且只能是常量,不能是变量。比如像下面这么写就是对的:
int a[5];
而像下面这么写就是错的:
int length = 5;
int a[length]; //错误
2) 因为数组长度只能是常量,所以它的长度不能在函数运行的过程当中动态地扩充和缩小。
3) 对于数组所占内存空间程序员无法手动编程释放,只能在函数运行结束后由系统自动释放,所以在一个函数中定义的数组只能在该函数运行期间被其他函数使用。
malloc函数的使用
那么动态内存是怎么造出来的?在讲如何动态地把一个数组造出来之前,我们必须要先介绍 malloc 函数的使用。
malloc 是一个系统函数,它是 memory allocate 的缩写。其中memory是“内存”的意思,allocate是“分配”的意思。顾名思义 malloc 函数的功能就是“分配内存”。要调用它必须要包含头文件<stdlib.h>。它的原型为:
# include <stdlib.h>
void *malloc(unsigned long size);
malloc 函数只有一个形参,并且是整型。该函数的功能是在内存的动态存储空间即堆中分配一个长度为size的连续空间。函数的返回值是一个指向所分配内存空间起始地址的指针,类型为 void*型。
简单的理解,malloc 函数的返回值是一个地址,这个地址就是动态分配的内存空间的起始地址。如果此函数未能成功地执行,如内存空间不足,则返回空指针 NULL。
辨析
int i = 5; //静态分配
int *p = (int*)malloc(4); //动态分配
1:malloc是由程序员在堆栈动态开辟空间
2:返回值开辟空间的首地址,但是类型是void *,需要强制类型转换
3:分配的内存空间应该能整除类型所占的字节数
4:包含头文件malloc.h
5:只能用free(p)来释放p所指向的动态开辟的内存空间。
6:对动态内存空间的操作,用*p来操作。
7:可以用多个指针指向这个动态空间
8:当有多个指针只向这个动态空间时,只能用free一个指针,多次重复释放要被报错
9:可以将动态开辟的的内存指针作为函数参数
试一试:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
int main()
{
int length, i; //length是数组的长度,i是循环变量
scanf("%d", &length);
int *p = (int *)malloc(20); //构造一个一维数组,长度是4字节 * 5个=20字节
if (length > 5)
{
printf("长度超出了5个,需要重新申请长度。\n");
p = (int*)realloc(p, length * 4);
}
for (i = 0; i < length; i++) //初始化
{
p[i] = i;
}
for (i = 0; i < length; i++) //输出
{
printf("%4d", p[i]);
}
free(p);
system("pause");
return 0;
}
实例
#include <stdio.h>
#include <time.h> //必不可少头文件:随机数
#include <stdlib.h> //必不可少头文件:动态分配空间
void GetRandomNumber(int* a, int n)
{
srand((unsigned int)time(NULL));
int i;
for (i = 0; i < n; i++)
{
a[i] = rand() % 100;
}
}
void show(int* a, int n)
{
int i;
for (i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
}
int main()
{
int* a = NULL;
int n;
scanf("%d", &n);
a = (int*)malloc(sizeof(int) * n);
GetRandomNumber(a, n);
show(a, n);
return 0;
}
二维动态数组
简单实现:
//动态的二维数组(最原始实现)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <time.h> //必不可少头文件
#include <stdlib.h> //必不可少头文件
void GetRandomNumber(int** a, int n)
{
srand((unsigned int)time(NULL));
int i, j;
for (i = 0; i < n; i++)
{
a[i] = (int*)malloc(sizeof(int) * n); //表明每行有n个元素位置
for (j = 0; j < n; j++)
{
a[i][j] = rand()%100;
}
}
}
void show(int** a, int n)
{
int i, j;
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
printf("%d ", a[i][j]);
}
printf("\n第%d行完毕!\n", i+1);
}
}
int main()
{
int n = 100;
int** a; //申明一个二维数组指针、二维指针变量
a = (int**)malloc(sizeof(int*) * n); //表明二维数组总共有n行
GetRandomNumber(a, n);
show(a, n);
return 0;
}
逻辑严密一点:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void InitArray(char** a, int n)
{
int i, j;
for (i = 0; i < n; i++)
{
a[i] = (char*)malloc(sizeof(char) * n);
if (a[i] == NULL) //如果没有判空操作,上一行代码则会发出警告:“取消对NULL指针的引用”
{
return;
}
for (j = 0; j < n; j++)
{
a[i][j] = 'a';
}
}
}
void ShowArray(char** a, int n)
{
int i, j;
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
printf("%c ", a[i][j]);
}
printf("\n一行输出完了\n");
}
}
int main()
{
char** a;
int n = 100;
a = (char**)malloc(sizeof(char*) * n); //这里千万不能写为” sizeof(char) * n”!!!
InitArray(a, n);
ShowArray(a, n);
return 0;
}
结果:
注意:
释放内存:
释放二维动态数组内存
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void InitArray(char** a, int n)
{
int i, j;
for (i = 0; i < n; i++)
{
a[i] = (char*)malloc(sizeof(char) * n);
if (a[i] == NULL) //如果没有判空操作,上一行代码则会发出警告:“取消对NULL指针的引用”
{
return;
}
for (j = 0; j < n; j++)
{
a[i][j] = 'a';
}
}
}
void ReleaseArray(char** a, int n)
{
int i;
for (i = 0; i < n; i++)
{
free(*(a + i));
}
}
void ShowArray(char** a, int n)
{
int i, j;
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
printf("%c ", a[i][j]);
}
printf("\n一行输出完了\n");
}
}
int main()
{
char** a;
int n = 100;
a = (char**)malloc(sizeof(char*) * n);
InitArray(a, n);
ShowArray(a, n);
ReleaseArray(a, n);
return 0;
}
区分行列:
区分行列的动态二维数组
#include <stdio.h>
#include <stdlib.h>
int main()
{
int** a;
int i, j;
int row, column; //行,列
row = 2; column = 3;
/*
2行3列为:
第一行第一列 第一行第二列
第二行第一列 第二行第二列
*/
a = (int**)malloc(sizeof(int*) * row);
for (i = 0; i < row; i++)
{
a[i] = (int*)malloc(sizeof(int) * column);
for (j = 0; j < column; j++)
{
a[i][j] = i * j;
}
}
for (i = 0; i < row; i++)
{
for (j = 0; j < column; j++)
{
printf("%d ", a[i][j]);
}
printf("\n");
}
return 0;
}
/*
输出:
0 0 0
0 1 2
*/
二维动态数组的使用方式总结
a.声明:int **a;
b.给内存:a=(int **)malloc(二维数的行数 * seizeof(int*));
for(i=0;i<二维数组的行数;i++)
a[i]=(int *)malloc(每行有多少个元素 * sizeof(int));
c.即可以如常规的二维数组使用;