我设法重现了仅打印一个部分字符串的错误行为。
这和你的使用情况有关sprintf
.
C如何处理char
arrays?
在 C 中使用数组时,必须首先为其分配内存。动态或静态,都没关系。假设您分配了足够的内存 10char
s.
char my_string[10];
在没有初始化它的情况下,它包含无意义的字符。
让我们假装my_string
包含"qwertyuiop"
.
假设你想填充my_string
用字符串foo
。你用sprintf
.
sprintf(my_string, "foo");
C 如何用 3 个字符填充 10 个槽?
它用 3 个字符填充前 3 个槽。然后,它用“字符串结尾”字符填充第四个槽。这表示为'\0'
,当它通过编译器时被转换为“字符串结尾”字符。
所以,在你的命令之后,my_string
包含"foo\0tyuiop"
。如果打印出来my_string
, C 知道不打印出后面的无意义字符\0
.
这有什么关系MPI_Gather
?
MPI_Gather
从不同进程收集数组,并将它们全部放入一个进程的一个数组中。
如果你有"foo\0tyuiop"
在进程 0 上和"bar\0ghjkl;"
在过程 1 中,它们被组合成"foo\0tyuiopbar\0ghjkl;"
.
正如您所看到的,进程 1 中的数组出现在进程 0 中的“行尾”字符之后。C 会将进程 1 中的所有字符视为无意义。
一个不完整的解决方案
而不是尝试打印所有rcv_string
立即承认有“字符串结尾”字符分散在各处。然后,根据字符串来自的进程,打印出具有不同“字符串开头”位置的字符串。
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
int rank, size;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
int part_str_len = 18;
char *my_string;
char *rcv_string;
if ((my_string = malloc(part_str_len*sizeof(char))) == NULL){
MPI_Abort(MPI_COMM_WORLD,1);
}
if ((rcv_string = malloc(part_str_len*size*sizeof(char))) == NULL){
MPI_Abort(MPI_COMM_WORLD,1);
}
sprintf(my_string, "%dr%dg%db%dl\n",255,255,255,0);
MPI_Gather(my_string,18,MPI_CHAR,rcv_string,18,MPI_CHAR,0,MPI_COMM_WORLD);
if (rank == 0) {
printf("%s",rcv_string);
}
char *cat_string;
if ((cat_string = malloc(part_str_len*size*sizeof(char))) == NULL){
MPI_Abort(MPI_COMM_WORLD,1);
}
if (rank == 0){
int i;
sprintf(cat_string, "%s", rcv_string);
for (i = 1; i < size; i++){
strcat(cat_string, &rcv_string[part_str_len*i]);
}
}
if (rank == 0) {
printf("%s",cat_string);
}
free(my_string);
free(rcv_string);
free(cat_string);
MPI_Finalize();
return 0;
}