MPI传输含动态数组结构体遇段错误:BYTE数组方案求助
MPI传输含动态数组的结构体时出现段错误
尝试发送包含动态分配数组的结构体,将结构体内容复制到动态BYTE数组中传输,但运行时出现段错误,代码如下:
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <mpi.h> // I read MPI_BYTE is an unsigned char typedef unsigned char BYTE; typedef struct Message { int id; int detectNr; char *detection; } Msg; int main() { int size, rank; MPI_Init(NULL, NULL); MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); if (size < 2) { printf("Invalid number of processes.\n"); return -1; } // initialize an empty message Msg msg = {.id = 1, .detectNr = 0, .detection = NULL}; // here we should take the measurements // for now suppose there are 10 msg.detectNr = 10; msg.detection = malloc(sizeof(char) * msg.detectNr); for (int i = 0; i < msg.detectNr; i++) msg.detection[i] = 'a' + i; if(rank != 0) { // put the data inside a buffer of BYTE int bufferSize = sizeof(int) + sizeof(int) + sizeof(char) * msg.detectNr; BYTE *buffer = malloc(sizeof(BYTE) * bufferSize); memcpy(buffer, &msg.id, sizeof(int)); memcpy(buffer + sizeof(int), &msg.detectNr, sizeof(int)); memcpy(buffer + (2 * sizeof(int)), &msg.detection, sizeof(char) * msg.detectNr); // send buffer to process 0 MPI_Send(buffer, bufferSize, MPI_BYTE, 0, 0, MPI_COMM_WORLD); free(buffer); free(msg.detection); } else { for (int i = 1; i < size; i++) { int bufferSize; BYTE *buffer; MPI_Status status; // initialize an empty message Msg rcv= {.id = 0, .detectNr = 0, .detection = NULL}; // probe for an incoming message from process zero MPI_Probe(i, 0, MPI_COMM_WORLD, &status); // when probe returns, the status object has the size and other // attributes of the incoming message // get the message size MPI_Get_count(&status, MPI_BYTE, &bufferSize); printf("\nProcess %d: buffer size: %d\n", rank, bufferSize); // allocate a buffer to hold the incoming data buffer = malloc(sizeof(BYTE) * bufferSize); // now receive the message with the allocated buffer MPI_Recv(buffer, bufferSize, MPI_BYTE, i, 0, MPI_COMM_WORLD, &status); // copy the data from the buffer to the message memcpy(&rcv.id, buffer, sizeof(int)); memcpy(&rcv.detectNr, buffer + sizeof(int), sizeof(int)); memcpy(&rcv.detection, buffer + (2 * sizeof(int)), sizeof(char) * rcv.detectNr); printf("Process %d: id: %d\n", rank, rcv.id); printf("Process %d: detectNr: %d\n", rank, rcv.detectNr); printf("Process %d: detection: %s\n", rank, rcv.detection); free(rcv.detection); free(buffer); } } MPI_Finalize(); return 0; }
运行后报错信息:
Process 0: buffer size: 18 Process 1: id: 1 Process 1: detectNr: 10 YOUR APPLICATION TERMINATED WITH THE EXIT STRING: Segmentation fault (signal 11)
错误原因
发送端数据复制错误:
发送端复制detection数组时,错误使用了&msg.detection(指针变量的地址),实际应该直接使用msg.detection(指向数组首元素的指针)。&msg.detection复制的是指针本身的值,而不是数组的实际内容,导致接收端收到的是无效地址而非数组数据。接收端内存未分配:
接收端的rcv.detection初始为NULL,直接调用memcpy(&rcv.detection, ...)是将数据写入NULL指针的地址空间,这会直接触发段错误。正确做法是先根据接收到的detectNr为rcv.detection分配内存,再将缓冲区的数组数据复制到该内存中。字符串打印越界:
原代码中detection数组没有终止符'\0',使用printf("%s")打印时会越界读取内存,可能引发未定义行为。
解决方案
修改发送端和接收端的关键代码部分:
修改后的完整代码
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <mpi.h> typedef unsigned char BYTE; typedef struct Message { int id; int detectNr; char *detection; } Msg; int main() { int size, rank; MPI_Init(NULL, NULL); MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); if (size < 2) { printf("Invalid number of processes.\n"); return -1; } Msg msg = {.id = 1, .detectNr = 0, .detection = NULL}; msg.detectNr = 10; // 分配内存时多留一个字节存终止符,避免打印越界 msg.detection = malloc(sizeof(char) * (msg.detectNr + 1)); for (int i = 0; i < msg.detectNr; i++) msg.detection[i] = 'a' + i; // 添加字符串终止符 msg.detection[msg.detectNr] = '\0'; if(rank != 0) { // 缓冲区大小包含终止符 int bufferSize = sizeof(int) + sizeof(int) + sizeof(char) * (msg.detectNr + 1); BYTE *buffer = malloc(sizeof(BYTE) * bufferSize); memcpy(buffer, &msg.id, sizeof(int)); memcpy(buffer + sizeof(int), &msg.detectNr, sizeof(int)); // 直接复制数组内容,而非指针地址 memcpy(buffer + (2 * sizeof(int)), msg.detection, sizeof(char) * (msg.detectNr + 1)); MPI_Send(buffer, bufferSize, MPI_BYTE, 0, 0, MPI_COMM_WORLD); free(buffer); free(msg.detection); } else { for (int i = 1; i < size; i++) { int bufferSize; BYTE *buffer; MPI_Status status; Msg rcv= {.id = 0, .detectNr = 0, .detection = NULL}; MPI_Probe(i, 0, MPI_COMM_WORLD, &status); MPI_Get_count(&status, MPI_BYTE, &bufferSize); printf("\nProcess %d: buffer size: %d\n", rank, bufferSize); buffer = malloc(sizeof(BYTE) * bufferSize); MPI_Recv(buffer, bufferSize, MPI_BYTE, i, 0, MPI_COMM_WORLD, &status); memcpy(&rcv.id, buffer, sizeof(int)); memcpy(&rcv.detectNr, buffer + sizeof(int), sizeof(int)); // 先为接收数组分配内存 rcv.detection = malloc(sizeof(char) * (rcv.detectNr + 1)); // 复制数组内容到分配好的内存 memcpy(rcv.detection, buffer + (2 * sizeof(int)), sizeof(char) * (rcv.detectNr + 1)); printf("Process %d: id: %d\n", rank, rcv.id); printf("Process %d: detectNr: %d\n", rank, rcv.detectNr); printf("Process %d: detection: %s\n", rank, rcv.detection); free(rcv.detection); free(buffer); } } MPI_Finalize(); return 0; }
关键修改点
- 发送端:
- 将
memcpy(..., &msg.detection, ...)改为memcpy(..., msg.detection, ...),复制数组实际内容。 - 为
msg.detection多分配一个字节,添加'\0'终止符,避免打印越界。
- 将
- 接收端:
- 在复制数组数据前,先根据
rcv.detectNr为rcv.detection分配内存。 - 将
memcpy(&rcv.detection, ...)改为memcpy(rcv.detection, ...),将数据写入分配好的内存空间。
- 在复制数组数据前,先根据
内容的提问来源于stack exchange,提问作者Scotty
相关产品推荐
相关产品推荐

