为什么我的动态二维字符数组中的值会被覆盖?
Why are the values in my dynamic 2D char array being overwritten?
我正尝试在 Linux 上用 C 语言构建一个进程记录器,但无法正确完成。我希望它有 3 个列:USER、PID、COMMAND。我正在使用 ps aux
的输出并尝试将其动态附加到数组。也就是说,对于每一行 ps aux
输出,我想在我的数组中添加一行。
这是我的代码。 (为了保持输出简短,我只对 sublime 进行 grep。但这可以是任何东西。)
#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
和 [= 中的值 7194
在哪里18=]来自).
我在这里做错了什么?是否有可能使输出看起来像 puts(line)
?
的输出
如有任何帮助,我们将不胜感激!
strtok
returns 指向它处理的字符串的指针。该字符串始终存储在变量 line
中。所以数组中的所有指针都指向内存中的同一个位置。
正如@Lundin 在评论中所写,这里没有二维数组,只有一维指针数组。
strtok
的 return 值是指向您标记化的字符串的指针。 (通过用 '[=11=]'
覆盖其后的第一个分隔符,使令牌以 null 终止。)
当您使用 fgets
读取新行时,您会覆盖该行的内容和所有标记,而不仅仅是上次解析的标记,指向该行的实际内容。 (指向先前标记的指针仍然有效,但这些位置的内容发生变化。)
有几种方法可以解决这个问题。
- 您可以制作保存字符数组的令牌和
strcpy
解析的内容。
- 您可以使用(非标准)
strdup
复制已解析的标记,它为堆上的字符串分配内存。
- 您可以读取一组行,这样标记就真正独一无二了。
我正尝试在 Linux 上用 C 语言构建一个进程记录器,但无法正确完成。我希望它有 3 个列:USER、PID、COMMAND。我正在使用 ps aux
的输出并尝试将其动态附加到数组。也就是说,对于每一行 ps aux
输出,我想在我的数组中添加一行。
这是我的代码。 (为了保持输出简短,我只对 sublime 进行 grep。但这可以是任何东西。)
#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
和 [= 中的值 7194
在哪里18=]来自).
我在这里做错了什么?是否有可能使输出看起来像 puts(line)
?
如有任何帮助,我们将不胜感激!
strtok
returns 指向它处理的字符串的指针。该字符串始终存储在变量 line
中。所以数组中的所有指针都指向内存中的同一个位置。
正如@Lundin 在评论中所写,这里没有二维数组,只有一维指针数组。
strtok
的 return 值是指向您标记化的字符串的指针。 (通过用 '[=11=]'
覆盖其后的第一个分隔符,使令牌以 null 终止。)
当您使用 fgets
读取新行时,您会覆盖该行的内容和所有标记,而不仅仅是上次解析的标记,指向该行的实际内容。 (指向先前标记的指针仍然有效,但这些位置的内容发生变化。)
有几种方法可以解决这个问题。
- 您可以制作保存字符数组的令牌和
strcpy
解析的内容。 - 您可以使用(非标准)
strdup
复制已解析的标记,它为堆上的字符串分配内存。 - 您可以读取一组行,这样标记就真正独一无二了。