如何逐行读取特定格式文件存入向量并实现MPI分发代码
问题描述
需要编写C程序读取特定格式的整数文件:首行是整数总数,后续每行一个随机整数,示例如下:
4 2 7 8 17
或
3 9 23 14
要求逐行读取文件并将整数存入向量,之后拆分向量分发到多个MPI进程执行后续任务。
尝试先统计文件行数再创建数组存储元素,但未成功,附上尝试代码:
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <mpi.h> int main( int argc, char *argv[]) { int rank, world_size; int root; int i; MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank); if (rank == 0) { char Line[100]; char c; int count_lines=0; FILE *fp = fopen("Input_16.txt","r"); for (c = getc(fp); c != EOF; c = getc(fp)) if (c == '\n') // Increment count if this character is newline count_lines = count_lines + 1; int array[count_lines]; for (i=0; i<count_lines; i++) array[i]=fgets(Line,100,fp); printf("Prints: %c \n",array[i]); } MPI_Finalize(); }
问题分析与修正
原代码核心问题
- 文件指针位置错误:统计行数时已将指针读到EOF,后续
fgets无法读取内容,需重置指针到文件开头。 - 类型不匹配:
fgets返回字符串指针,直接赋值给int数组完全错误,需用atoi或sscanf转成整数。 - 逻辑错误:首行是整数个数,统计的行数比实际整数多1,应直接读取首行数值作为数组大小,而非统计行数。
- 代码块缩进错误:第二个
for循环的printf未包含在循环体内,仅执行一次。 - 缺失错误检查:未判断
fopen是否成功,文件不存在时会直接崩溃。
修正后的完整代码
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <mpi.h> int main(int argc, char *argv[]) { int rank, world_size; int i, total_numbers; int *data = NULL; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &world_size); if (rank == 0) { FILE *fp = fopen("Input_16.txt", "r"); if (!fp) { perror("Failed to open file"); MPI_Abort(MPI_COMM_WORLD, 1); } // 读取首行的整数总数 if (fscanf(fp, "%d", &total_numbers) != 1) { fprintf(stderr, "Failed to read total number count\n"); fclose(fp); MPI_Abort(MPI_COMM_WORLD, 1); } // 动态分配内存(避免变长数组兼容性问题) data = malloc(total_numbers * sizeof(int)); if (!data) { perror("Failed to allocate memory"); fclose(fp); MPI_Abort(MPI_COMM_WORLD, 1); } // 读取后续所有整数 for (i = 0; i < total_numbers; i++) { if (fscanf(fp, "%d", &data[i]) != 1) { fprintf(stderr, "Failed to read number at index %d\n", i); free(data); fclose(fp); MPI_Abort(MPI_COMM_WORLD, 1); } } fclose(fp); // 验证读取结果 printf("Rank 0 read %d numbers: ", total_numbers); for (i = 0; i < total_numbers; i++) { printf("%d ", data[i]); } printf("\n"); } // -------------------------- MPI分发部分 -------------------------- // 广播总个数给所有进程 MPI_Bcast(&total_numbers, 1, MPI_INT, 0, MPI_COMM_WORLD); // 计算每个进程分配的数量(处理不均分情况) int local_count = total_numbers / world_size; int remainder = total_numbers % world_size; if (rank < remainder) { local_count++; } // 每个进程分配本地内存 int *local_data = malloc(local_count * sizeof(int)); if (!local_data) { perror("Failed to allocate local memory"); MPI_Abort(MPI_COMM_WORLD, 1); } // 使用MPI_Scatterv分发数据(支持不均分场景) int *sendcounts = NULL; int *displs = NULL; if (rank == 0) { sendcounts = malloc(world_size * sizeof(int)); displs = malloc(world_size * sizeof(int)); int offset = 0; for (i = 0; i < world_size; i++) { sendcounts[i] = (i < remainder) ? local_count : (local_count - 1); displs[i] = offset; offset += sendcounts[i]; } } MPI_Scatterv(data, sendcounts, displs, MPI_INT, local_data, local_count, MPI_INT, 0, MPI_COMM_WORLD); // 验证本地数据 printf("Rank %d received %d numbers: ", rank, local_count); for (i = 0; i < local_count; i++) { printf("%d ", local_data[i]); } printf("\n"); // 释放内存 if (rank == 0) { free(data); free(sendcounts); free(displs); } free(local_data); MPI_Finalize(); return 0; }
关键说明
- 文件读取优化:直接读取首行的整数总数,省去统计行数的冗余操作;用
fscanf直接读取整数,避免字符串转换步骤,更高效可靠。 - 内存安全:用
malloc动态分配内存替代变长数组,提升兼容性;增加文件打开、内存分配的错误检查,避免程序崩溃。 - MPI分发逻辑:
- 用
MPI_Bcast广播总个数,让所有进程知晓需分配的内存大小。 - 处理不均分场景:余数部分的进程多分配一个元素。
- 用
MPI_Scatterv替代MPI_Scatter,支持不同进程接收不同数量的数据。
- 用
- 错误处理:任何步骤失败时调用
MPI_Abort终止所有进程,避免部分进程挂起。
内容的提问来源于stack exchange,提问作者Davey_flan
相关产品推荐
相关产品推荐

