繁体   English   中英

从C中的extern char环境复制字符串

[英]Copying strings from extern char environ in C

我有一个关于extern char **environ 我正在尝试制作一个计算环境列表大小的C程序,将其复制到字符串数组(字符数组),然后使用冒泡排序按字母顺序对其进行排序。 它将根据格式值以name=valuevalue=name顺序打印。

我尝试使用strncpy将字符串从环境获取到新数组,但是字符串值空了。 我怀疑我正在尝试以无法使用的方式使用环境,因此我正在寻求帮助。 我试图在网上寻求帮助,但是此特定程序非常有限。 不能使用system() ,但是我在网上找到的唯一帮助告诉我编写一个程序来进行此系统调用。 (这帮助)。

#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
        }
    }

这是我的代码,非常感谢您的帮助。 为什么这很难找到主题? 是否缺乏必要性?

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

在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++;
   }
 }

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

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

这是一些简单的代码,使用标准C库qsort()函数进行排序,并以dup_str()的名称模拟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;
}

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

请注意,将对内存分配进行错误检查,并根据标准错误而不是标准输出报告错误。

显然,如果您喜欢编写和调试排序算法,则可以避免使用qsort() 请注意,字符串比较需要使用strcmp() ,但是在对指针数组进行排序时,不能将strcmp()直接与qsort()一起使用,因为参数类型错误。

对我来说,部分输出是:

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

如果要对值而不是名称进行排序,则必须做一些更艰苦的工作。 您需要定义您希望看到的输出。 有多种处理此类问题的方法。

要获取环境变量,您需要像这样声明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个字符可能太短。 例如,我的LS_COLORS变量很大,至少有1500个字符。 您可能需要基于strlen(environ[i])+1 list[i] = malloc调用。

另一件事:您的交换

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 如果您想退出循环,请执行do break 您正在寻找strlen(list[i]) :这将给您字符串的长度。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM