You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)

错误原因

  1. 发送端数据复制错误:
    发送端复制detection数组时,错误使用了&msg.detection(指针变量的地址),实际应该直接使用msg.detection(指向数组首元素的指针)。&msg.detection复制的是指针本身的值,而不是数组的实际内容,导致接收端收到的是无效地址而非数组数据。

  2. 接收端内存未分配:
    接收端的rcv.detection初始为NULL,直接调用memcpy(&rcv.detection, ...)是将数据写入NULL指针的地址空间,这会直接触发段错误。正确做法是先根据接收到的detectNr为rcv.detection分配内存,再将缓冲区的数组数据复制到该内存中。

  3. 字符串打印越界:
    原代码中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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 21:35:59