学习任务:
掌握指针和结构、文件的结合使用。掌握形参与实参
首先通过读书,掌握c语言文本文件的基本概念和基本操作。熟悉文本文件的读写及fopen/fclose,fscanf/fprintf等函数。
作业:使用读写文件的矩阵乘法
要求:读出指定文本文件中各矩阵,计算多矩阵相乘后结果,并将结果写入另一文本文件中。
文件名任意;如输入文件:input.txt; 输出文件out.txt
输入文件格式:将多个矩阵记录在文件中,多个矩阵以空行分隔。类似:
1 3 2
2 5 4
3
8
12
(上述文件包括2个矩阵,分别为2*3和3*1的)
(提示:对于多矩阵,可使用结构数组/结构指针)
头文件 matrix.h
/********************************************************************
头文件中应该包含的内容:
*函数原型
*使用#define或const定义的符号常量
*结构声明
*类声明
*模板声明
*内联函数 P262
*********************************************************************/
#ifndef MATRIX_H_
#define MATRIX_H_
#include<stdio.h>
struct mat //矩阵结构体
{
int row; //矩阵行数
int column; //矩阵列数
int** pointer; //矩阵的头指针
};
const char sou_pos[] = "matrix.txt"; //输入文件位置
const char dst_pos[] = "output.txt"; //输出文件名(默认在当前目录下)
void task( ); //任务函数
int count_mat ( FILE* file ); //读取指定文件中矩阵个数
void eye_create( int N , mat* d_mat ); //创造一个N*N的单位阵
void copy_mat ( mat* s_mat , mat* d_mat ); //深拷贝一个矩阵到另一个位置
void release ( mat* d_mat ); //释放指定位置的row*column内存
void mat_create( mat* d_mat ); //创造一个row*column的矩阵
void mat_mulp ( mat* s_mat1 , mat* s_mat2 , mat* d_mat ); //计算两个矩阵的乘积
void mat_output( FILE* file , mat* d_mat ); //将矩阵写入到指定文件
void getfeature( FILE* file , mat* s_mat ); //得到文件下一个矩阵的行数和列数
void input_mat ( FILE* file , mat* s_mat ); //从文本文件中读取一个矩阵的信息到一个mat中
#endif
函数文件 task2_fun.cpp
#include<stdio.h> //定义输入输出函数
#include<stdlib.h> //定义杂项函数及内存分配函数
#include<string.h> //字符串处理
#include"matrix.h" //自定义函数
/*******************************************************
函数名称:task
函数参数:无
返回参数:无
函数功能:执行整个任务
调用函数:
********************************************************/
void task( )
{
FILE* file; //文件指针
int count = 0; //记录矩阵个数
mat* mat1 , *mat2 , *d_mat; //源结构体及结果结构体
mat1 = ( mat* ) malloc( sizeof( mat ) );
mat2 = ( mat* ) malloc( sizeof( mat ) );
d_mat = ( mat* ) malloc( sizeof( mat ) );
if( fopen_s( &file , sou_pos , "r" ) ) //返回值为1,说明打开文件失败
{
printf( "Can't open file!" );
exit( 0 );
}
else
{
count = count_mat( file );
rewind( file ); //记得一定要重定向,上一次已经改变了file指针的位置!!!!!!!
getfeature( file , mat2 ); //得到第一个矩阵的信息,getfeature不改变file位置
eye_create( mat2->row ,mat1); //mat1先存一个单位阵
for( int i = 0; i < count;i++ )
{
if( i != 0 )
{
getfeature( file , mat2 ); //将下一个矩阵的行列信息存入mat2,
}
input_mat ( file , mat2 ); //文件中读取的矩阵存入mat2中
mat_mulp( mat1 , mat2 , d_mat ); //d_mat = mat1 * mat2
release ( mat1 ); //释放mat1的空间
copy_mat( d_mat , mat1 ); //mat1 = d_mat
release ( d_mat ); //释放d_mat的空间
}
fclose( file );
}
if( fopen_s( &file , dst_pos , "w" ) ) //返回值为1,说明打开文件失败
{
printf( "Can't open file!" );
exit( 0 );
}
else
{
mat_output( file , mat1 ); //最终的结果在mat1中
}
return;
}
/****************************************************************
函数名称:getfeature
函数参数:文件指针位置
返回参数:文件中矩阵的个数
函数功能:读取指定文件中下一个矩阵的行数和列数
调用函数:无
注意:此函数并没有改变file指针的位置!!!
*****************************************************************/
void getfeature( FILE* file , mat* s_mat )
{
FILE* sub_file = file;
char buf[1024];
long offset;
offset = ftell( file );
s_mat->row = 0;
s_mat->column = 0;
while( fgets( buf , 1024 ,file ) != NULL )
{
if( buf[0] == '\n' ) //读到某个矩阵的末尾
{
break;
}
else
{
s_mat->row++;
if( s_mat->column != 0 )
{
continue; //列数已读取完毕
}
int len = strlen( buf );
for( int i = 0; i < len; i++ )
{
if( buf[i] == ' ' )
{
s_mat->column++;
}
}
s_mat->column++;
}
}
fseek( file , offset , SEEK_SET ); //指针重定向!!!!!!!重点一定要放在这里,不要放在break前面,要不然对最后一个矩阵有问题
printf( "矩阵为%d X %d" , s_mat->row , s_mat->column );
}
/**********************************************************
函数名称:count_mat
函数参数:读取文件的指针
返回参数:文件中矩阵的个数
函数功能:读取指定文件中矩阵的个数
调用函数:无
***********************************************************/
int count_mat( FILE* file )
{
int count = 0;
char buf[1024];
while( fgets( buf , 1024 , file ) != NULL )
{
if( buf[0] == '\n' )
{
count++;
continue;
}
}
count++;
printf( "%d个矩阵" , count );
return count;
}
/*******************************************************************
函数名称:eye_create
函数参数:欲创建的单位阵的行数,创建的矩阵的地址
返回参数:无
函数功能:创建一个N*N的矩阵
调用函数:mat_create(mat* d_mat)
*******************************************************************/
void eye_create( int N , mat* d_mat )
{
d_mat->row = N;
d_mat->column = N;
mat_create( d_mat );
for( int i = 0; i < N; i++ )
{
for( int j = 0; j < N; j++ )
{
if( i == j )
{
d_mat->pointer[i][j] = 1;
}
else
{
d_mat->pointer[i][j] = 0;
}
}
}
return;
}
/*******************************************************************
函数名称:mat_output
函数参数:欲写入的文件指针,欲记录的mat结构体指针
返回参数:无
函数功能:创建一个指定名称的txt文件并将最后计算的矩阵相乘结果记录其中
调用函数:release( mat* d_mat )
*******************************************************************/
void mat_output( FILE* file , mat* d_mat )
{
int row = d_mat->row;
int column = d_mat->column;
for( int i = 0; i < row; i++ )
{
for( int j = 0; j < column; j++ )
{
fprintf( file , "%5d" , d_mat->pointer[i][j] );
}
fprintf( file , "\n" );
}
release( d_mat );
return;
}
/*******************************************************************
函数名称:release
函数参数:指向欲释放内存的mat结构体指针
返回参数:无
函数功能:释放指定mat结构体中pointer的内存
调用函数:无
*******************************************************************/
void release( mat* d_mat )
{
for( int i = 0; i < d_mat->row; i++ )
{
if( d_mat->pointer[i] != NULL )
{
free( d_mat->pointer[i] );
}
}
if( d_mat->pointer != NULL )
{
free( d_mat->pointer );
}
d_mat->pointer = NULL;
d_mat->row = 0;
d_mat->column = 0;
return;
}
/*******************************************************************
函数名称:copy_mat
函数参数:源mat结构体指针,目的mat结构体指针
返回参数:无
函数功能:将d_mat结构体初始化并将s_mat完全复制到d_mat中
调用函数:mat_create( mat* )
*******************************************************************/
void copy_mat( mat* s_mat , mat* d_mat )
{
d_mat->row = s_mat->row;
d_mat->column = s_mat->column;
mat_create( d_mat );
for( int i = 0; i < d_mat->row; i++ )
{
for( int j = 0; j < d_mat->column; j++ )
{
d_mat->pointer[i][j] = s_mat->pointer[i][j];
}
}
return;
}
/*******************************************************************
函数名称:mat_create
函数参数:目的mat结构体指针
返回参数:无
函数功能:申请d_mat结构体的二级指针的内存
调用函数:无
*******************************************************************/
void mat_create( mat* d_mat )
{
d_mat->pointer = ( int** ) malloc( d_mat->row * sizeof( int* ) );
for( int i = 0; i < d_mat->row; i++ )
{
d_mat->pointer[i] = ( int* ) malloc( d_mat->column * sizeof( int ) );
}
return;
}
/*******************************************************************
函数名称:mat_mulp
函数参数:包含相乘的两矩阵的结构体指针,目的结构体指针
返回参数:无
函数功能:计算两矩阵相乘结构并存入目的结构体中
调用函数:mat_create(mat* d_mat)
*******************************************************************/
void mat_mulp( mat* s_mat1 , mat* s_mat2 , mat* d_mat )
{
int result = 0;
d_mat->row = s_mat1->row;
d_mat->column = s_mat2->column;
mat_create( d_mat );
for( int i = 0; i < s_mat1->row; i++ )
{
for( int j = 0; j < s_mat2->column; j++ )
{
result = 0;
int m = 0;
for( int k = 0; k < s_mat2->row; k++ )
{
result = result + s_mat1->pointer[i][m] * s_mat2->pointer[k][j];
m++;
}
d_mat->pointer[i][j] = result;
printf( "%d " , d_mat->pointer[i][j] );
}
printf( "\n" );
}
}
/*******************************************************************
函数名称:input_mat
函数参数:文件指针,输入结构体指针
返回参数:无
函数功能:将文件指针指向的矩阵写入一个mat结构体中
调用函数:mat_create(mat* d_mat)
*******************************************************************/
void input_mat( FILE* file , mat* s_mat )
{
mat_create( s_mat );
printf( "\n" );
for( int i = 0; i < s_mat->row; i++ )
{
for( int j = 0; j < s_mat->column; j++ )
{
fscanf( file , "%d" , &s_mat->pointer[i][j] );
printf( "%d " , s_mat->pointer[i][j] );
}
printf( "\n" );
}
if( !feof( file ) )
{
fseek( file , 4L , SEEK_CUR ); //一个\n占两个字节0D0A 对Windows系统
}
}
主函数文件 main.cpp
/**********************************************************************
关于文件指针的操作http://www.cnblogs.com/whiteyun/archive/2009/08/08/1541822.html
可以使用fun(const int* a[])防止指针内容被修改
函数指针
double pam(int)
double (*pf)(int)
pf=pam
引用必须在声明时就将它初始化,而不能像指针一样先声明后赋值
返回指向结构的引用效率更高 P234
默认参数一定要在最右边 P241
int fseek(FILE *stream, long offset, int fromwhere) 函数设置文件指针stream的位置
函数设置文件指针stream的位置。如果执行成功,stream将指向以fromwhere(偏移起始位置:
文件头0(SEEK_SET),当前位置1(SEEK_CUR),文件尾2(SEEK_END))为基准,偏移offset(指针偏移量)
个字节的位置。如果执行失败(比如offset超过文件自身大小),则不改变stream指向的位置。
long ftell(FILE *stream) 用于得到文件位置指针当前位置相对于文件首的偏移字节数
rewind() 将文件内部的位置指针重新指向一个流(数据流/文件)的开头
*******************************************************************/
#include<stdio.h> //定义输入输出函数
#include<stdlib.h> //定义杂项函数及内存分配函数
#include"matrix.h" //自定义函数
int main( )
{
task( );
return 0;
}
这是我写的作业的2.0版本吧。第一次写的太渣,内存占用过多,还没有释放,程序结构、可读性、可维护性太差,好多功能都耦合在一起,于是重新写了一遍,这次结构应该算比较清晰的。
遇到的最大的问题就是文件指针的操作。当我调用count_mat()函数之后,不知道指针已经移动了(到文件尾为NULL),导致我以为是后面的参数传不进去,调试了好久,后面的读取矩阵的时候,也要注意文件指针的定位问题。这个确实的自己调试才能真正弄明白。
知识点:文件指针操作,浅拷贝与深拷贝,矩阵的计算