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

C++使用MPI如何收集各进程char字符串并逐进程打印输出

问题原因

你代码的核心错误有4处:

  1. 接收缓冲区溢出:你定义的receive数组初始化为"nothing",长度只有8字节(含末尾\0),但要接收的"received"长度是9字节,写入时越界破坏了内存数据。
  2. 打印逻辑错误:totalstring是按位移存储所有进程的完整字符串,你直接用totalstring[i]只会取到第i个字节的单个字符,自然是逐字符输出。
  3. 数组分配错误:new int[nbproc*sizeof(int)]写法错误,new运算符后面跟的是元素个数,不是字节数,多分配了几倍空间属于无用操作。
  4. 数组越界写入:你给totalstring分配了totlen大小的空间,却执行totalstring[totlen] = '\0',下标从0开始的情况下totlen属于越界位置。

修正后的代码

#include <iostream>
#include <cstring>
#include <mpi.h>
using namespace std;

int main(int argc, char** argv) {
    int rank, nbproc, taille;
    char name[80];
    
    char message[] = "preceived";
    int longueur = strlen(message); 
    const int len_buffer = 200;
    char Buffer_Hello[len_buffer];
    // 修正1:把receive数组改大,避免接收溢出
    char receive[20] = "nothing";    
    
    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &nbproc); 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);  
    MPI_Get_processor_name(name, &taille);
    
    sprintf(Buffer_Hello, "Hello from process %d among %d of the machine %s", rank, nbproc, name);
    
    // 调整发送时机,避免不必要的缓冲占用
    if (rank != 0) {
        MPI_Send(Buffer_Hello, len_buffer, MPI_CHAR, 0, rank+10, MPI_COMM_WORLD);
    }

    if (rank == 4) {
        MPI_Send(&message[1], longueur, MPI_CHAR, 5, 2, MPI_COMM_WORLD);
    }
 
    if (rank == 5) {   
        MPI_Recv(receive, 20, MPI_CHAR, 4, 2, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
    }

    int mylen = strlen(receive);
    // 修正2:数组分配不需要乘sizeof(int)
    int* recvcounts = new int[nbproc]; 
    MPI_Gather(&mylen, 1, MPI_INT, recvcounts, 1, MPI_INT, 0, MPI_COMM_WORLD); 
    
    int totlen = 0; 
    int* displs = new int[nbproc];

    if(rank == 0) {
        displs[0] = 0;
        totlen += recvcounts[0] + 1; 
        for(int i=1; i < nbproc; i++) {
            totlen += recvcounts[i]+1; 
            displs[i] = displs[i-1] + recvcounts[i-1] + 1; 
        }
    }

    char* totalstring = new char[totlen]; 

    if(rank == 0) {
        for (int i=0; i<totlen; i++) 
            totalstring[i] = '\0'; 
    }
  
    MPI_Gatherv(receive, mylen, MPI_CHAR,
                totalstring, recvcounts, displs, MPI_CHAR,
                0, MPI_COMM_WORLD);

    if(rank == 0) {
        // 先打印进程0的信息
        cout << Buffer_Hello << endl;
        cout << totalstring + displs[0] << endl;
        // 修正3:从displs[i]位置开始打印对应进程的完整字符串
        for(int i = 1; i < nbproc; i++) {
            MPI_Recv(Buffer_Hello, len_buffer, MPI_CHAR, i, i+10, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
            cout << Buffer_Hello << endl;
            cout << totalstring + displs[i] << endl;
        }
    }

    delete[] recvcounts;
    delete[] displs;
    delete[] totalstring;
    MPI_Finalize(); 
    return 0;
}

修改说明

  • 把receive数组扩容到20字节,完全容纳可能的字符串,避免接收溢出
  • 修正数组分配逻辑,new时只传元素个数即可
  • 打印时用totalstring + displs[i]获取对应进程的字符串首地址,输出完整字符串
  • 初始化totalstring时直接填充\0,避免后续字符串输出异常
  • 补充了内存释放逻辑,避免内存泄漏
  • 调整了非0进程发送Buffer_Hello的逻辑,只在非0进程执行发送,避免进程0做无用发送

内容的提问来源于stack exchange,提问作者Jejouze

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 15:24:03