码迷,mamicode.com
首页 > 编程语言 > 详细

见微知著——依旧是矩阵乘法算法!

时间:2015-12-18 23:59:27      阅读:342      评论:0      收藏:0      [点我收藏+]

标签:

  博主上大二了,接触linux自我认为还是一个有小小追求的人,觉得一直漂浮在上层没有根基,于是还是想看看linux内核,便重新看是看pointers on c扎实c语言基础。不再急功近利,不再认为看完书就学到了知识,实践出真知,自己动手才是王道。不多说,就用一个以前我写过的例子嘲讽以前的我吧!

  还是一样的,pointers on c的chapter8的第五个编程小题。

  函数原型

void matrix_multiply ( int *m1 , int *m2 ,int *r , int x , int y , int z );
//其中m1是第一个数组,m2是第二个数组,m3是输出数组x,y是m1数组的行列号,y,z是m2的行列号

  先看第一遍的

void matrix_multiply ( int *m1 , int *m2 , 
		int *r , int x , int y , int z )
{
	int i = 0;
	int j = 0;
	int k = 0;

	for ( i = 0 ; i < x ; i++ )
	{
		for ( k = 0 ; k < z ; k++ )
		{
			for ( j = 0 ; j < y ; j++ )
			{
				*(*(&r+i)+k) += (*(*(&m1+i)+j)) * (*(*(&m2+j)+k));
			}
		}
	}
}

  算法很简单,我的思路再反复确定之后认为没有错误,但是编译执行之后一直会出现,segmentation fault (core dumped)也就是传说中的数组越界。想了一下才明白问题的所在——r,m1,m2不是数组名!

  假设有数组名a,那么&a会是当前的地址,并且假设a是一维数组,那么&a就是从列指针转化为行指针,具体的实例可以假设int a[10];只需要printf一下a+1的地址和&a+1的地址结果就显而易见!但是在这个题目中,不会将m1,m2,r当做数组名的,即使你将函数原型改为int m1[]这样的也可以,这里会当做是变量来处理。由于这里函数原型中的形参是*m1,*m2,*r这样的列指针,我想当然的认为这里可以转化行指针来处理,但实际上并不可以,因为这里是在堆栈中的变量。

  那么问题究竟出在哪里那?

  参考一个例子

  firstfile.c:

  int a[10];

  int *b=a;

  ...

  secondfile.c:

  extern int *a;

  extern int b[];

  ...

  那么a[3]和b[3]的值会是什么那?这里由于第二个文件中会把a当做指针变量处理,取出指针变量位置中存储的值,再加上3*sizeof(int)得到一个值,再对得到的值解引用,取出那个位置中的值,而实际上a是数组名,那么最后的结果就是取出(a[0]+12)这个地址的值。(这个访问一般情况下是非法的)

  而这里会将b当做是数组名,直接将b的地址加上12再解引用取值,这里也会是非法访问的。

  其实仔细想想,就是一个根本区别——变量会创建空间,而数组名不会!

  经过以上的思想挣扎之后我发现这里只能用列指针来进行操作,所以第二遍我就是对的了,嘿嘿!

  

void matrix_multiply ( int *m1 , int *m2 , 
		int *r , int x , int y , int z )
{
	int	i = 0;
	int j = 0;
	int k = 0;

	for ( i = 0 ; i < x ; i++ )
	{
		for ( k = 0 ; k < z ; k++ )
		{
			for ( j = 0 ; j < y ; j++ )
			{
				*(r+i*z+k) += *(m1+i*y+j) * *(m2+j*z+k);
			}
		}
	}
}

  虽然只是改了一行,但是我还是感觉蛮好的!

见微知著——依旧是矩阵乘法算法!

标签:

原文地址:http://www.cnblogs.com/zzlpp/p/5058388.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!