• 微信公众号:美女很有趣。 工作之余,放松一下,关注即送10G+美女照片!

程序设计基础

开发技术 开发技术 2天前 5次浏览

变量与指针

变量
数的表示形式
数据的输入与输出

指针变量与指针的指针

简化表达式

共性与可变性的分析

数组与指针

数组的数组与指针

数组的数组–二维数组
二维数组int data[2][3] = {{1,2,3},{4,5,6}};,可以用下面的表格来描述
程序设计基础
data是由data[0],data[1]这两个元素构成的一维数组。
data[0]是由data[0][0],data[0][1],data[0][2]三个元素构成的一维数组。
data[1]是由data[1][0],data[1][1],data[1][2]三个元素构成的一维数组。


请注意,以下是精彩段落

由于表达式中的数组名可以被解释为指针.
data是指向data[0]的指针

data == &data[0]
*data == data[0]

data[0]是指向data[0][0]的指针

data[0] == &data[0][0]
*data[0] == data[0][0]

故有

data == &data[0] == &(&data[0][0])
*data == data[0] == &data[0][0]
**data == data[0][0]

练习
若有定义int a[2][3] = {{1},{2,3}},则 a[1][0]的值是多少
分析:
二维数组是基于一维数组变化而来了,我们可以将题目中的数据拆成一维数组来分析

int a0[3] = {1};
int a1[3] = {2,3};

故由此可知,题目答案为 2

数组的指针
按照变量的声明规则,将data取出后,余下的就是data数据类型。这是开发编译器时约定的。
对一维数组int test[2]int [2]就是test的数据类型,test是指向int的指针,即int *
对于二维数组int a[2][3] ,int [2][3]就是a的数据类型。
a[0] a[1]的数据类型是int [3]
a是指向a[0]的指针,而a[0]的数据类型是int [3],即a是指向int [3]的指针,即 int (*)[3]

将二维数组作为函数参数
方法一

int sum (int data[][2], int size);

方法二

int sum(int (*pdata)[2], int size);

用法

int data[3][2] = {{1,2},{3,4},{5,6}};
int total = sum(data, 3);

对二维数组的常用操作
获取二维数组的相关数据
sizeof(data)整个二维数组的空间大小
sizeof(data[0])一行元素的空间大小
sizeof(data[0][0])单个元素的空间大小
sizeof(data)/sizeof(data[0]) 行数
sizeof(data[0])/sizeof(data[0][0])列数
sizeof(data)/sizeof(data[0][0])元素个数

找到二维数组中的最大元素
可以将二维数组转为一维数组来进行搜索

int max(int *pdata, int size);

用法

int data[3][2] = {{1,2},{3,4},{5,6}};
int n = sizeof(data)/sizeof(data[0][0]);
int max = max((int *)data, n);

清空二维数组

memset(data, 0, sizeof(data));

对二维数组的某一行进行清0

memset(data[row], 0, sizeof(data[0]));

对二维数组的某一列进行清0
由于数组是按行而不按列存储,因此操作二维数组中的列元素就相对复杂一些。
下面是对数组data的第i列清0

int data[row][col],(*pData)[col],i;
for(pData = &data[0];pData < &data[row];pData++)
	(*pData)[i] = 0;	//对某行的i列的元素清零

or

int data[row][col],i
for(int r = 0; r < row; r ++)
	data[r][i] = 0;	//对r行i列的元素清零

字符串与指针

动态分配内存

程序在运行时请求内存,被分配的空间称之为HEAP,虽然计算机在硬件上不直接支持HEAP,但是C函数库(stdlib.h)提供了申请与释放的函数,在运行时根据需要申请内存空间,在不需要时释放。

malloc()

void *malloc(unsigned int size);
	void *表示函数返回值是一个指针,从C99开始,void *类型指针可以赋值给摺有类型的指针变量
	size 为所需内存的字节数

eg.
int *pi = malloc(sizeof(int));
if (NULL != pi)
{
	//成功申请到内存
}
else
{
	//没有申请到内存
}

calloc()

比malloc()函数更好用函数

void *calloc (size_t nmeb, size_t size);

为nmeb个元素的数组分配内存,每个元素的大小为size 字节。在内存分配成功后,会将这片内存全部清0。

如,申请n个整数的数组,并初始化为0
pi = calloc(n,sizeof(int));

技巧:将calloc函数的第一个参数输入“1”,就可以为任何类型的数据项分配空间。
申请一块类型空间,同时清为0

struct point {int x,y;} *pi;
pi = calloc(1, sizeof(struct point));

realloc()

在原有分配的内存基础上,扩充内存。

void *realloc(void *pointer, unsigned int size);

alloc是allocate分配的缩写,前缀re是重新分配的意思。
如果原内存后面还有足够空闲内存的话,realloc()只是修改分配表,还是返回原内存地址;
如果没有足够空闲内存,realloc()会申请新的内存,然后将原内存的数据复制到新内存中,原内存将被free()掉,realloc()返回新的内存地址。

比如,有5个int型元素的数组变量需要分配内存

int *pi = malloc(5*sizeof(int));

但是在使用时发现,申请的空间不够了,需要10个才够用,那么需要先释放内存,然后再申请新的内存。

free(pi);
pi = malloc(10*sizeof(int));

为了保留原来的数据,需要再做一些工作

int *temp = pi;	//让temp 指向原内存
pi = malloc(10*sizeof(int));	让pi指向新内存
memcpy(pi,temp,5*sizeof(int));	将原内存的数据复制到新内存
free(temp);	//释放原内存

但上面的工作也可以由下面的一句话来完成

pi = realloc(pi,10*sizeof(int))

free()

通常内存申请与释放配对使用,当申请的内存使用完毕后,如果不及时释放掉,就会导致可用内存空间减少,也就是内存泄露,进而影响程序的正常运行。

void free(void *pointer);

悬空指针的出现

char *pi = malloc(5);
free(pi);	//释放掉pi所指向的内存块,但是pi依旧指向这块空间,此时的pi被称为悬空指针
strcpy(pi,"abc");	//错误

更好的方法

由于free()函数不会检查传入的参数是否为NULL,也不会返回前将指针设置为NULL,因此为了安全起见,要创建自己的free函数。

void safer_free(void **pp)
{
	if (pp != NULL && *pp != NULL)
	{
		free(*pp);
		*pp = NULL;
	}
}

为了简化使用,可以将其定义成宏,可以省略类型转换和传递指针的地址
#define SAFER_FREE(p) safer_free((void **)&p)
其调用形式如下:

int pi = malloc(sizeof(int));
SAFER_FREE(pi);

程序员灯塔
转载请注明原文链接:程序设计基础
喜欢 (0)