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


      博主上大二了,接触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);
    			}
    		}
    	}
    }
    

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

  • 相关阅读:
    gnuplot 让您的数据可视化
    sort
    sed
    AWK
    STA之RC Corner再论
    STA之RC Corner拾遗
    网络编程释疑之:TCP半开连接的处理
    Task 任务内部揭秘
    Task 线程任务
    【转】SQL Server、Oracle、MySQL和Vertica数据库常用函数对比
  • 原文地址:https://www.cnblogs.com/zzlpp/p/5058388.html
Copyright © 2020-2023  润新知