1.1 data.c/concat_datas
data concat_datas(data *d, int n)
{
int i
data out = {0}
for(i = 0
data new = concat_data(d[i], out)
// i = 0时,因为out = {0},表明默认初始化其中所有的元素为0值,对于指针变量而言,那就是空指针,
// free()函数可以接受一个空指针,此时free()函数将无作为,但不会出错;当i != 1时,out等于上一次循环得到的new,
// 在concat_data()函数中,会置其shallow元素值为1,也即进行浅层释放,为什么进行浅层释放呢?
// 整个的concat_datas函数在合并矩阵,在合并每一个小矩阵时,小矩阵的数据并没有进行深拷贝(深拷贝是指内容拷贝),
// 而是直接将小矩阵每一行的指针变量赋值给了大矩阵的对应行的指针变量(浅拷贝)(可以回看data.c文件中的concat_matrix()函数for循环中的赋值操作,
// m1.vals[i]是指向二维数组每一行开头的指针变量,也即复制的是指针变量本身,而不是指针变量所指的值,这就是浅拷贝),
// 所以小矩阵out与得到的新的大矩阵实际会共享数据,因此,下面只能释放out.X.vals及out.y.vals用于存储每一行指针变量的堆内存,
// 而不能内释放用于存储真实数据的堆内存,也即只能进行浅层释放,不能进行深层释放。
free_data(out)
// 置out等于新得到的大矩阵new,此时out.X.vals以及out.y.vals存储的指向每一行数据的指针变量包括
// 目前为止得到的整个大矩阵的所有行
out = new
}
return out
}
1.2 data.c/concat_data
/*
** 合并某一块图片数据到大data中并返回
** 输入: d1 待合并的data块
** d2 待合并的data块
** 返回: data类型数据
** 碎碎念(TODO):为什么总是动不动返回或者传入data等其他结构体实例呢,传指针不是更快么:(
*/
data concat_data(data d1, data d2)
{
data d = {0};
d.shallow = 1;
// 合并图片数据至d.X中
d.X = concat_matrix(d1.X, d2.X);
// 合并图片的标签数据至d.y中
d.y = concat_matrix(d1.y, d2.y);
return d;
}
1.3 data.c/concat_matrix
matrix concat_matrix(matrix m1, matrix m2)
{
int i, count = 0;
matrix m;
m.cols = m1.cols;
m.rows = m1.rows+m2.rows;
m.vals = calloc(m1.rows + m2.rows, sizeof(float*));
for(i = 0; i < m1.rows; ++i){
m.vals[count++] = m1.vals[i];
}
for(i = 0; i < m2.rows; ++i){
m.vals[count++] = m2.vals[i];
}
return m;
}
2.1 data.c/free_data()
void free_data(data d)
{
if(!d.shallow){
// 深层释放堆内存(注意虽然输入是d.X,d.y,但不是直接释放d.X,d.y,这二者在data结构体中根本连指针都不算。
// 在free_matrix()中是逐行释放d.X.vals和d.y.vals的内存,再直接释放d.X.vals和d.y.vals)
free_matrix(d.X)
free_matrix(d.y)
}else{
// 浅层释放堆内存
free(d.X.vals)
free(d.y.vals)
}
}
2.2 matrix.c/free_matrix()
void free_matrix(matrix m)
{
int i;
for(i = 0; i < m.rows; ++i) free(m.vals[i]);
free(m.vals);
}