市场上的玉簪都带土吗?

小说:市场上的玉簪都带土吗?作者:安密龙更新时间:2019-05-19字数:99854

学C语言,一定绕不过指针这一大难关,而指针最让人头疼的就是各种指向关系,一阶的指针还比较容易掌握,但一旦阶数一高,就很容易理不清楚其中的指向关系,现在我将通过杨辉三角为例,我会用四种方法从内存的角度简单分析动态二维数组,若有不足或错误之处,还请指出!

在讲这之前,以一维数组为例,先重新认识一下数组:

int array[5] = {1, 2, 3, 4, 5};

首先数组名称是该数组的首地址常量,即数组名称就是指针,就有&array[0] == array!

那么我们可以推出*array == array[0] == 1;

这里引入一个概念“指类”(这个概念没有在正规场合出现过,只是我为了方便分析而引入的),其表示指针所指向的空间的类型!array是一个int*类型的指针,那么它的指类就是int类型(比较容易的记忆,就是指针的类型去掉一个*就是其指类!);

其实array[0]是一个表象,其本质应该是*array ;

我们的array是局部变量,在系统堆栈中申请了sizeof(int)*5,即20字节大小的空间,用于存放5个整型数!

因为array的值是该数组首元素的地址(即首地址),那么array+1的意思就是给该数组的首地址这个值增加了一个int类型空间字节数,也就是4字节,从而array+1的值就应该是该数组的下一个int类型元素的地址,即&a[1],所以就有array+1 == &a[1];

那么array加几加几,加的实际就是多少个指类空间大小!

那么*array就可以理解成*(array + 0),同理,array[1] ==*(array + 1),array[2] == *(array + 2)......

上式还可以由加法交换律变形得到array[1] == *(1 + array),那么array[1]透过这一本质来看,其也可以变形成1[array];

*这样写编译器不但不会报错,而且连警告都不会有,但不建议这样书写!

*如果对我上文提到的系统堆栈不了解的话,强烈建议看一看下面的这个博客,后文全部涉及到内存!

*后文我不会用array[index]这种方式,而是用*(array + index)这种最本质的方式

C语言中关于形参与实参关系

 

这里我们先讲一讲系统堆栈和系统堆:

        操作系统将内存分成:系统数据,系统功能调用(核心代码)区域;用户代码和数据区域;系统堆栈区;系统堆区;

        系统堆栈是由编译器自动分配,用于存放函数的参数值,局部变量的值等;

        而系统堆区是由程序员通过malloc/calloc函数自主申请的空间,系统堆的空间要远远大于系统堆栈的空间,但切记,一定要在使用完毕后,通过free函数释放掉所申请的空间。

*C语言(包括C++)不像Java那样有gc(垃圾回收)机制,gc机制大大减少了程序员的工作量,程序员在Java中通过new申请空间时,只需负责申请,gc会帮助善后(实则是Java的JVM),而C/C++需要程序员自主释放,所以java相比C++要容易掌握!

----------------------------------------------------------------------------------------------------------------------------------

 

杨辉三角:

                                                 

关于杨辉三角如何计算得到的问题,我就不累赘了(*^_^*)

方法一:

如图,我们给出了一个六层的杨辉三角,通常的话,我们会给一个静态的二维数组用来存放这个杨辉三角:

int yangHui[row][row];

但是这会生成一个row行×row列的空间,而我们实际用到的的空间要比这小,除了最后一层,其他每一层都会有浪费的空间,为了避免这样的情况,我们就应该想到动态的数组,根据当前行数,通过malloc/calloc动态申请每一层的空间。所以,我们可以用如下的方式表示这个二维数组:

int *yangHui[row];

这种定义看起来很奇怪,其实它完全就是一个一维数组,这个一维数组的大小是row,只不过这个一维数组的每一个元素是由int *类型所组成,其本质就是一个一维的指针数组!我们可以把它定义成以下这种形式:

typedef int* type;
type yangHui[row];

这样看的话就比较好理解了,他就是一个类型为type类型的一维数组!而type就是int*,那么,这个一维数组存放的每一个元素就应该是一个int*类型的的值,那么这个值完全就可以是一个int类型的一维数组的首地址!即yangHui数组里面存放的是row个一维数组的首地址!

铺垫工作完成,下来我们就来生成杨辉三角:

*由于杨辉三角往后的数字越来越大,故以下代码都用long类型!先假定要生成的杨辉三角的层数num = 5;

void creatYangHuiOne(int num);

void creatYangHuiOne(int num) {
	long *yangHui[num];
	int row;
	int col;
	
	for (row = 0; row < num; row++) {
		*(yangHui + row) = (long *) calloc(sizeof(long), row + 1);
		for (col = 0; col <= row; col++) {
			*(*(yangHui + row) + col) = (row == col || col == 0) ? 1 : *(*(yangHui + row - 1) + col - 1) + *(*(yangHui + row - 1) + col);		
		}
	}
        // 关于showYangHuiTriangle函数我会在最后给出,只是为了打印好看,不做重点! 
	showYangHuiTriangle(yangHui, num);
	for (row = 0; row < num; row++) {
		free(*(yangHui + row));
	}
}


多次循环得到下列关系

方法二:

void creatYangHuiTwo(int num);
void destoryYangHui(long **yangHui, int num);

void creatYangHuiTwo(int num) {
	long **yangHui = NULL;
	int row;
	int col;
	
	yangHui = (long **) calloc(sizeof(long *), num);

	for (row = 0; row < num; row++) {
		*(yangHui + row) = (long *) calloc(sizeof(long), row + 1);
		for (col = 0; col <= row; col++) {
			*(*(yangHui + row) + col) = (row == col || col == 0) ? 1 : *(*(yangHui + row - 1) + col - 1) + *(*(yangHui + row - 1) + col);
		}
	}
	showYangHuiTriangle(yangHui, num);
	destoryYangHui(yangHui, num);
}

void destoryYangHui(long **yangHui, int num) {
	int row;
	 
	for (row = 0; row < num; row++) {
			free(*(yangHui + row));
		}
	free(yangHui);
}

方法三:

long **creatYangHuiThree(int num);

long **creatYangHuiThree(int num) {
	long **yangHui = NULL;
	int row;
	int col;
	
	yangHui = (long **) calloc(sizeof(long *), num);

	for (row = 0; row < num; row++) {
		*(yangHui + row) = (long *) calloc(sizeof(long), row + 1);
		for (col = 0; col <= row; col++) {
			*(*(yangHui + row) + col) = (row == col || col == 0) ? 1 : *(*(yangHui + row - 1) + col - 1) + *(*(yangHui + row - 1) + col);
		}
	}
	
	return yangHui;
}

与方法二基本一样,只不过返回值是long **类型,将creatYnaghHuiThree函数中yangHui的值即在系统堆中申请的空间的首地址addressRow作为返回值返回!该空间不会随着子函数的调用结束而消失,需要在主函数中释放!

 

方法四:

void creatYangHuiFour(long ***yangHui, int num);

void creatYangHuiFour(long ***yangHui, int num) {
	int row;
	int col;

	*yangHui = (long **) calloc(sizeof(long *), num);

	for (row = 0; row < num; row++) {
		*((*yangHui) + row) = (long *) calloc(sizeof(long), row + 1);
		for (col = 0; col <= row; col++) {
			*(*((*yangHui) + row) + col) = (row == col || col == 0) ? 1 : *(*((*yangHui) + row - 1) + col - 1) + *(*((*yangHui) + row -1 ) + col);
		}
	}
}

当creatYangHuiFour函数调用结束,栈底栈顶指针回落,系统堆栈申请的子函数的局部变量都奔释放,但是主函数的yangHui空间的值通过指针运算已经由NULL变为ddressRow,而这个空间是在系统堆中申请的,不会随着子函数的调用结束而消失,即该空间还未被释放,故需要在主函数中释放!

打印函数及主函数:

void showYangHuiTriangle(long **yangHui, int num);
int getMaxNumberLength(long num);

int getMaxNumberLength(long num) {
	int count = 1;
	
	while (num/=10) {
		++count;
	}
	
	return count;
}

void showYangHuiTriangle(long **yangHui, int num) {
	int len = getMaxNumberLength(*(*(yangHui + num -1) + num/2));
	int i;
	int j;
	int row;
	int col;
	
	for (row = 0; row < num; row++) {
		for (i = 0; i < num - row - 1; i++) {
				for (j = 0; j < len; j++) {
				printf(" ");
				}
		}
		for (col = 0; col < row + 1; col++) {
			printf("%ld", *(*(yangHui + row) + col));
			if (getMaxNumberLength(*(*(yangHui + row) + col)) < len) {
				for (j = 0; j < len - getMaxNumberLength(*(*(yangHui + row) + col)); j++) {
					printf(" ");
				}
			}
			for (j = 0; j < len; j++) {
				printf(" ");
			}
		}
		printf("
");
	}
}

int main() {
	long **yangHui = NULL;
	int num;
	
	printf("请输入行数:
");
	scanf("%d", &num);	
	creatYangHuiOne(num);
	creatYangHuiTwo(num);
	//yangHui = creatYangHuiThree(num);
	creatYangHuiFour(&yangHui, num);
	showYangHuiTriangle(yangHui, num);
	destoryYangHui(yangHui, num);

	return 0;
}

输出如图:

感谢您的阅读(*^_^*)

我在CSDN放了一份以杨辉三角为例,从内存角度简单分析C语言中的动态二维数组

当前文章:http://cnsdbtzg.com/array/hg9pdid0df.html

发布时间:2019-05-19 12:07:01

火棘的种植方法简单吗? 2013年柿子树价格_市场最新报价 优质现货,海量供应粉红色蔷薇,超低价格精品质量, 剑麻是常绿植物吗? 2.2米蜀桧价格多少钱一棵 85元上车价 40公分栗子树多少钱 5500元一棵上车价格 一家专注于优质与低价玫瑰种苗批发的苗圃! 紫花苜蓿蛋白含量高吗? 产量大的牧草有哪些? 种植波斯菊最重要的是什么呢?

34056 79979 99704 81075 36578 93764 41134 85551 59431 73600 28187 62662 46176 72580 65985 90921 67389 93151 64586 71869 38259 60418 58041

我要说两句: (0人参与)

发布