c - 为什么动态二维字符数组中的值被覆盖?

标签 c arrays linux dynamic realloc

我正在尝试在 Linux 上用 C 语言构建一个进程记录器,但无法正确实现。我希望它有 3 列:用户、PID、命令。我正在使用 ps aux 的输出并尝试将其动态附加到数组中。也就是说,对于每行 ps aux 输出,我想向数组添加一行。

这是我的代码。 (为了保持输出简短,我只 grep for sublime。但这可以是任何东西。)

#define _BSD_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main()
{
    char** processes = NULL;
    char* substr = NULL;
    int n_spaces = 0;
    int columns = 1;

    char line[1024];
    FILE *p;
    p = popen("ps -eo user,pid,command --sort %cpu | grep sublime", "r");
    if(!p)
    {
        fprintf(stderr, "Error");
        exit(1);
    }

    while(fgets(line, sizeof(line) - 1, p))
    {
        puts(line);
        substr = strtok(line, " ");
        while(substr != NULL)
        {
            processes = realloc(processes, sizeof(char*) * ++n_spaces);

            if(processes == NULL)
                exit(-1);

            processes[n_spaces - 1] = substr;

            // first column user, second PID, third all the rest
            if(columns < 2)//if user and PID are already in array, don't split anymore
            {
                substr = strtok(NULL, " ");
                columns++;
            }
            else
            {
                substr = strtok(NULL, "");
            }
        }
        columns = 1;
    }
    pclose(p);

    for(int i = 0; i < (n_spaces); i++)
        printf("processes[%d] = %s\n", i, processes[i]);

    free(processes);

    return 0;

}

最后 for 循环的输出如下所示。

processes[0] = user
processes[1] = 7194
processes[2] = /opt/sublime_text/plugin_host 27184

processes[3] = user
processes[4] = 7194
processes[5] = /opt/sublime_text/plugin_host 27184

processes[6] = user
processes[7] = 27194
processes[8] = /opt/sublime_text/plugin_host 27184

processes[9] = user
processes[10] = 27194
processes[11] = /opt/sublime_text/plugin_host 27184

但是,从 puts(line) 我知道数组实际上应该包含以下内容:

user       5016 sh -c ps -eo user,pid,command --sort %cpu | grep sublime
user       5018 grep sublime
user      27184 /opt/sublime_text/sublime_text
user      27194 /opt/sublime_text/plugin_host 27184

所以,显然所有的值都被覆盖了,我不明白为什么......(另外,我不明白processes[0]中的值7194在哪里= 7194processes[4] = 7194 来自)。

我在这里做错了什么?是否有可能使输出看起来像 puts(line) 的输出?

如有任何帮助,我们将不胜感激!

最佳答案

strtok 的返回值是指向您标记的字符串的指针。 (通过用 '\0' 覆盖其后的第一个分隔符,该 token 已变为空终止。)

当您使用 fgets 读取新行时,您会覆盖该行的内容,并且所有标记(而不仅仅是上次解析的标记)都指向该行的实际内容。 (指向先前标记的指针仍然有效,但这些位置的内容发生了变化。)

有几种方法可以解决这个问题。

  • 您可以使用 token 来保存字符数组和 strcpy 解析的内容。
  • 您可以使用(非标准)strdup 复制已解析的标记,它为堆上的字符串分配内存。
  • 您可以读取行数组,因此标记确实是唯一的。

关于c - 为什么动态二维字符数组中的值被覆盖?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33566804/

相关文章:

c - 当在最后一部分之前发送失败时,ZeroMQ 多部分消息会发生什么情况?

c - 存储一个大于20的数字! (阶乘)

C 内存分配 : Fixed-length array in a struct in a struct

linux - 来自 udev 规则的参数未传递到 perl 脚本

java - 将 Git 存储库导入 Linux Eclipse (3.8) 并将其作为 Java 项目运行/编译

php - UTF-8贯穿始终

c++ - 什么属于 "Data Oriented Design"?

c - 字符串数组 : Delete original array and then return copy

php - 在不保留原始键的情况下自然地对平面数组进行排序

ios - 如何使用按钮在 2 个部分之间移动单元格?