传递给方法后,struct 中的字符串变成奇怪的符号

String inside struct become weird symbols after passing to a method

我有一个名为 task 的结构。它是一个包含结构计时和命令的链表。用来存放我在某个时间要执行的命令:

// and here is the struct command:
struct argument {
    size_t length; // length of the data string
    char *data;
};
typedef struct argument argument;

struct command {
    int argc; // amount of arguments(words) in argv
    argument *argv; // here I already tried put argument **argv
};
typedef struct command command;

我用 task *this_task = malloc(sizeof(task)); 初始化任务 并使用 command *cmds = malloc(sizeof(command)).

初始化命令

我用这个方法添加命令:

command *addToCommand(command *cmd, size_t argSize, char *arg) {
    argument *currentArgument = malloc(sizeof(argument) + argSize * sizeof(char));
    if (currentArgument == NULL) {
        cmd = NULL;
        return cmd;
    }
    currentArgument->length = argSize;
    currentArgument->data = arg;

    if (cmd == NULL) {
        cmd = malloc(sizeof(command));
        if (cmd == NULL) return cmd;
        cmd->argv = malloc(sizeof(argument));
        cmd->argv[0] = *currentArgument;
        cmd->argc = 1;
    } else {
        cmd->argc++;
        cmd->argv = realloc(cmd->argv, (cmd->argc) * sizeof(argument));
        cmd->argv[cmd->argc-1] = *currentArgument;
    }
    return cmd;
}

然后设置为this_task->cmd = cmds;

现在的问题是:就在我完成所有这些之后,我用 printf( "%s\n", this_task->cmd->argv[0].data) 打印了我任务的第一个 argv,它显示了 'test-0' 应该的样子。

但是当我将它发送到另一个方法时,比如 addTask(this_task),并再次打印它 在 addTask 方法的第一行 它显示了奇怪的符号像 "p

例如此代码:

void addTask(task *task_to_add) {
    printf("arg inside addTask = '%s'\n", task_to_add->cmd->argv[0].data);
   // i'm doing things here but even when everything is commented the bug happen 
}

printf("arg before addTask = '%s'\n", this_task->cmd->argv[0].data);
addTask(this_task);
printf("arg after addTask = '%s'\n", this_task->cmd->argv[0].data);

显示:

arg before addTask = 'test-0'
arg inside addTask = '`��'
arg after addTask = '`��'

在这个项目中,我将命令写入管道,并在上面的代码中读取它。在尝试制作一个最小的可重现示例时,我注意到当我从管道中删除部分读数并直接强制“test-0”的值时,它可以正常工作。那么问题是否因为我读取管道的方式而发生?我也尝试了“可能重复”的解决方案,但没有用。问题可能出在我如何从管道中读取。

我还注意到,如果我在显示“addTask 之前的 arg ...”之前没有任何其他 printf,显示“ ”之前的 arg,我评论它并写下“THIS PRINTF " 附近

我是如何编译的 运行:

gcc src/saturnd.c -o saturnd
gcc src/cassini.c  -o cassini
./saturnd
./cassini (in another terminal)

正在读取管道的代码:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <endian.h>

struct argument {
    size_t length;
    char *data;
};
typedef struct argument argument;

struct command {
    int argc;
    argument *argv;
};
typedef struct command command;

struct task {
    int id;
    struct timing *timing;
    command *cmd;
    struct task *next;
};
typedef struct task task;


struct timing {
    uint64_t minutes;
    uint32_t hours;
    uint8_t daysofweek;
};


int readHere;
task *tasks = NULL;

command *addToCommand(command *cmd, size_t argSize, char *arg) {
//    printf("adding to cmd %s\n", arg);
    argument *currentArgument = malloc(sizeof(argument) + argSize * sizeof(char));
    if (currentArgument == NULL) {
        cmd = NULL;
        return cmd;
    }
    currentArgument->length = argSize;
    currentArgument->data = arg;

    if (cmd == NULL) {
        cmd = malloc(sizeof(command));
        if (cmd == NULL) return cmd;
        cmd->argv = malloc(sizeof(argument));
        cmd->argv[0] = *currentArgument;
        cmd->argc = 1;
    } else {
        cmd->argc++;
        cmd->argv = realloc(cmd->argv, (cmd->argc) * sizeof(argument));
        cmd->argv[cmd->argc - 1] = *currentArgument;
    }
    return cmd;
}

void addTask(task *task_to_add) {
    printf("arg inside addTask = '%s'\n", task_to_add->cmd->argv[0].data);
}

int main() {
    char *readHere_path = "saturndReadPipe";
    mkfifo(readHere_path, S_IRWXU | S_IRWXG | S_IRWXO);
    readHere = open(readHere_path, O_RDONLY);

    task *this_task = malloc(sizeof(task));
    this_task->id = 0;

    struct timing *reply_time = malloc(sizeof(struct timing));
    reply_time->minutes = 5; // test vars
    reply_time->hours = 5; // test vars
    reply_time->daysofweek = 5; // test vars

    uint32_t reply_argc;
    read(readHere, &reply_argc, sizeof(reply_argc));
    reply_argc = be32toh(reply_argc);

    // reply_argc should be 2, because we wrote only 2 words "echo" and "test-0"

    command *cmds = NULL;
    for (int j = 0; j < (int) reply_argc; j++) {
        uint32_t argSize_uint;
        read(readHere, &argSize_uint, sizeof(argSize_uint));
        int argSize = be32toh(argSize_uint);
        int newSize = argSize + 1;
        char arg[newSize];
        int data_read = (int) read(readHere, &arg, argSize);
        arg[data_read] = '[=15=]';

        //printf("read '%s' from pipe\n", arg); // THIS PRINTF

        cmds = addToCommand(cmds, newSize, arg);
    }
    this_task->cmd = cmds;
    this_task->next = NULL;

    printf("arg before addTask = '%s'\n", this_task->cmd->argv[0].data);
    addTask(this_task);
    printf("arg after addTask = '%s'\n", this_task->cmd->argv[0].data);

    exit(0);
}

正在管道中写入的代码:

#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <endian.h>

int main() {

    char *writeHere_path = "saturndReadPipe";

    int writeHere = open(writeHere_path, O_WRONLY | O_TRUNC);

    uint32_t cmd_argc = htobe32(2);
    write(writeHere, &cmd_argc, sizeof(cmd_argc));

    // sending "echo"
    uint32_t length = htobe32(4);
    write(writeHere, &length, sizeof(length));
    char *cmd_data = "echo";
    uint8_t d[4];
    int j = 0;
    for (; j < 4; ++j)
        d[j] = cmd_data[j];
    write(writeHere, &d, sizeof(d));

    // sending "test-0"
    length = htobe32(4);
    write(writeHere, &length, sizeof(length));
    cmd_data = "test-0";
    uint8_t dd[4];
    j = 0;
    for (; j < 4; ++j)
        dd[j] = cmd_data[j];
    write(writeHere, &dd, sizeof(dd));

    exit(0);
}

你不复制字符串只分配指针给它。我会以不同的方式来做。

typedef struct argument {
    size_t length; // length of the data string
    char data[];
}argument;

typedef struct command {
    int argc; // amount of arguments(words) in argv
    argument *argv[];
}command;

command *addToCommand(command *cmd, const size_t argSize, const char *restrict arg) 
{
    int newargc = cmd ? cmd -> argc + 1 : 1;
    argument *currentArgument = malloc(sizeof(*currentArgument) + 
             (argSize + 1) * sizeof(currentArgument -> data[0]));  //if argsize includes null terminating character remove "+1"  
    if (currentArgument) 
    {
        currentArgument->length = argSize;
        strcpy(currentArgument->data, arg);

        cmd = realloc(cmd, sizeof(*cmd) + newargc * sizeof(cmd -> argv[0]));

        if(cmd)
        {
            cmd -> argc = newargc;
            cmd -> argv[newargc -1] = currentArgument;
        }
    }

    return cmd;
}