从C中的extern char environ复制字符串

时间:2018-04-28 01:42:40

标签: c strncpy environ

我有一个与name=value有关的问题。我试图创建一个计算环境列表大小的C程序,将其复制到字符串数组(字符数组数组),然后按字母顺序对其进行排序。它将以value=namestrncpy顺序打印,具体取决于格式值。

我尝试使用system()从environ获取字符串到我的新数组,但字符串值为空。我怀疑我试图以一种我无法做到的方式使用环境,所以我正在寻求帮助。我试图在网上寻求帮助,但这个特别的计划非常有限。我无法使用#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> extern char **environ; int main(int argc, char *argv[]) { char **env = environ; int i = 0; int j = 0; printf("Hello world!\n"); int listSZ = 0; char temp[1024]; while(env[listSZ]) { listSZ++; } printf("DEBUG: LIST SIZE = %d\n", listSZ); char **list = malloc(listSZ * sizeof(char**)); char **sorted = malloc(listSZ * sizeof(char**)); for(i = 0; i < listSZ; i++) { list[i] = malloc(sizeof(env[i]) * sizeof(char)); // set the 2D Array strings to size 80, for good measure sorted[i] = malloc(sizeof(env[i]) * sizeof(char)); } while(env[i]) { strncpy(list[i], env[i], sizeof(env[i])); i++; } // copy is empty??? for(i = 0; i < listSZ - 1; i++) { for(j = 0; j < sizeof(list[i]); j++) { if(list[i][j] > list[i+1][j]) { strcpy(temp, list[i]); strcpy(list[i], list[i+1]); strcpy(list[i+1], temp); j = sizeof(list[i]); // end loop, we resolved this specific entry } // else continue } } ,但我在网上找到的唯一帮助告诉我制作一个程序来进行此系统调用。 (这不是帮助)。

first = [1, 5, 8]
second = [0.5, 4]

combined = [(f,s) for f in first for s in second]

print(combined)
# [(1, 0.5), (1, 4), (5, 0.5), (5, 4), (8, 0.5), (8, 4)]

这是我的代码,非常感谢帮助。为什么这么难找?是缺乏必要性吗?

编辑:粘贴了错误的代码,这是一个关于同一主题的单独.c文件,但我在另一个文件上重新开始。

3 个答案:

答案 0 :(得分:1)

在unix环境中,环境是main的第三个参数。

试试这个:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[], char **envp)
{

   while (*envp) {
   printf("%s\n", *envp);
   *envp++;
   }
 }

答案 1 :(得分:1)

您的代码存在多个问题,包括:

  • listsorted分配'错误'尺寸(您乘以sizeof(char **),但应该乘以sizeof(char *),因为您正在分配char *数组{1}}。这个错误实际上不会对你造成伤害。使用sizeof(*list)可以避免这个问题。
  • listsorted中的元素分配错误的尺寸。您需要使用strlen(env[i]) + 1作为大小,记住允许终止字符串的null。
  • 您不检查内存分配。
  • 您的字符串复制循环使用strncpy(),不应该(实际上,您应该很少使用strncpy()),尤其是因为它只复制每个环境变量的4或8个字节(取决于无论你是在32位还是64位系统上,并且它不能确保它们是空终止字符串(只是使用strncpy()的众多原因之一
  • 您的“排序”代码的外部循环正常;你的内部循环是100%的假,因为你应该使用一个或另一个字符串的长度,而不是指针的大小,你的比较是单个字符,但你在那里使用strcpy()需要移动指针。
  • 您分配但不使用sorted
  • 您不打印已排序的环境以证明它已排序。
  • 您的代码缺少最终}

以下是一些使用标准C库qsort()函数进行排序的简单代码,并模拟POSIX strdup()dup_str()的名称下 - 如果您有POSIX,则可以使用strdup()

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

extern char **environ;

/* Can also be spelled strdup() and provided by the system */
static char *dup_str(const char *str)
{
    size_t len = strlen(str) + 1;
    char *dup = malloc(len);
    if (dup != NULL)
        memmove(dup, str, len);
    return dup;
}

static int cmp_str(const void *v1, const void *v2)
{
    const char *s1 = *(const char **)v1;
    const char *s2 = *(const char **)v2;
    return strcmp(s1, s2);
}

int main(void)
{
    char **env = environ;
    int listSZ;

    for (listSZ = 0; env[listSZ] != NULL; listSZ++)
        ;
    printf("DEBUG: Number of environment variables = %d\n", listSZ);

    char **list = malloc(listSZ * sizeof(*list));
    if (list == NULL)
    {
        fprintf(stderr, "Memory allocation failed!\n");
        exit(EXIT_FAILURE);
    }

    for (int i = 0; i < listSZ; i++)
    {
        if ((list[i] = dup_str(env[i])) == NULL)
        {
            fprintf(stderr, "Memory allocation failed!\n");
            exit(EXIT_FAILURE);
        }
    }

    qsort(list, listSZ, sizeof(list[0]), cmp_str);

    for (int i = 0; i < listSZ; i++)
        printf("%2d: %s\n", i, list[i]);

    return 0;
}

其他人指出,您可以使用原型main()通过第三个参数int main(int argc, char **argv, char **envp)来获取环境。请注意,Microsoft明确支持此功能。它们是正确的,但您也可以通过environ访问环境,即使在main()以外的函数中也是如此。变量environ在由任何头文件中声明的 not 中的POSIX定义的全局变量中是唯一的,因此您必须自己编写声明。

请注意,内存分配已经过错误检查,错误报告标准错误,而不是标准输出。

显然,如果您喜欢编写和调试排序算法,则可以避免使用qsort()。请注意,字符串比较需要使用strcmp()来完成,但是当您对指针数组进行排序时,由于参数类型错误,您不能直接使用strcmp() qsort()。< / p>

我的部分输出是:

DEBUG: Number of environment variables = 51
 0: Apple_PubSub_Socket_Render=/private/tmp/com.apple.launchd.tQHOVHUgys/Render
 1: BASH_ENV=/Users/jleffler/.bashrc
 2: CDPATH=:/Users/jleffler:/Users/jleffler/src:/Users/jleffler/src/perl:/Users/jleffler/src/sqltools:/Users/jleffler/lib:/Users/jleffler/doc:/Users/jleffler/work:/Users/jleffler/soq/src
 3: CLICOLOR=1
 4: DBDATE=Y4MD-
…
47: VISUAL=vim
48: XPC_FLAGS=0x0
49: XPC_SERVICE_NAME=0
50: _=./pe17

如果要对值而不是名称进行排序,则必须做一些更难的工作。您需要定义要查看的输出。有多种处理方式。

答案 2 :(得分:0)

要获取环境变量,您需要像这样声明main

int main(int argc, char **argv, char **env);

第三个参数是NULL - 终止的环境变量列表。参见:

#include <stdio.h>

int main(int argc, char **argv, char **environ)
{
    for(size_t i = 0; env[i]; ++i)
        puts(environ[i]);

    return 0;
}

这个输出是:

LD_LIBRARY_PATH=/home/shaoran/opt/node-v6.9.4-linux-x64/lib:
LS_COLORS=rs=0:di=01;34:ln=01;36:m
...

另请注意,代码中的sizeof(environ[i])无法获得您的长度 字符串,它可以获得指针的大小,所以

strncpy(list[i], environ[i], sizeof(environ[i]));

错了。此外,strncpy的重点是根据目的地限制, 不在源头上,否则如果源大于目的地,你 仍将溢出缓冲区。正确的电话会是

strncpy(list[i], environ[i], 80);
list[i][79] = 0;

请记住strncpy可能不会写'\0' - 终止字节 目的地不够大,所以你必须确保终止 串。另请注意,79个字符可能太短,无法存储env变量。例如,我的LS_COLORS变量 是巨大的,至少1500个字符长。您可能希望根据list[i] = malloc进行strlen(environ[i])+1来电。

另一件事:你的交换

strcpy(temp, list[i]);
strcpy(list[i], list[i+1]);
strcpy(list[i+1], temp);
j = sizeof(list[i]);
仅当所有list[i]指向相同大小的内存时,

才有效。由于list[i]是指针,更便宜的交换方式是 改为交换指针:

char *tmp = list[i];
list[i] = list[i+1];
list[i+1] = tmp;

这是更高效的,是一个O(1)操作,你不必担心如果 内存空间的大小不同。

我不知道的是,您对j = sizeof(list[i])有什么打算?不只 sizeof(list[i])返回一个指针的大小(它将是常量 对于所有list[i]),你为什么要搞乱里面的运行变量j? 块?如果您想离开循环,请执行break。你正在寻找 strlen(list[i]):这将为您提供字符串的长度。