Копирование строк из среды extern char в C

У меня есть вопрос, касающийся extern char **environ, Я пытаюсь создать программу на C, которая считает размер списка окружения, копирует его в массив строк (массив массивов символов), а затем сортирует его по алфавиту с помощью пузырьковой сортировки. Это будет печатать в name=value или же value=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 по той же теме, но я начал заново на другом файле.

3 ответа

Есть несколько проблем с вашим кодом, в том числе:

  • Выделение "неправильного" размера для list а также sorted (вы умножаете на sizeof(char **), но должен быть умножен на sizeof(char *) потому что вы выделяете массив char *, Эта ошибка на самом деле не повредит вам в этот раз. С помощью sizeof(*list) избегает проблемы.
  • Выделение неправильного размера для элементов в list а также sorted, Вам нужно использовать strlen(env[i]) + 1 для размера, помня, чтобы допустить нулевой символ, который завершает строку.
  • Вы не проверяете распределение памяти.
  • Ваш цикл копирования строк использует strncpy() и не должен (на самом деле, вы должны редко использовать strncpy()), не в последнюю очередь потому, что он копирует только 4 или 8 байтов каждой переменной среды (в зависимости от того, используете ли вы 32-разрядную или 64-разрядную систему), и это не гарантирует, что они являются нулевыми завершенными строками (просто одна из многих причин не использовать strncpy(),
  • Ваш внешний цикл вашего кода сортировки в порядке; Ваш внутренний цикл на 100% фальшивый, потому что вы должны использовать длину одной или другой строки, а не размер указателя, и ваши сравнения выполняются по одиночным символам, но затем вы используете strcpy() где вам просто нужно перемещать указатели.
  • Вы выделяете, но не используете sorted,
  • Вы не распечатываете отсортированную среду, чтобы продемонстрировать, что она отсортирована.
  • Ваш код отсутствует в финале },

Вот простой код, который использует стандартную библиотеку C qsort() функция для сортировки и имитации POSIX strdup() под именем dup_str() - вы могли бы использовать strdup() если у вас есть POSIX для вас.

#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 уникален среди глобальных переменных, определенных 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

Если вы хотите отсортировать значения вместо имен, вам нужно проделать более сложную работу. Вам нужно определить, какой вывод вы хотите увидеть. Есть несколько способов обработки такого рода.

В среде 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++;
   }
 }

Чтобы получить переменные среды, вам нужно объявить 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]): это даст вам длину строки.

Другие вопросы по тегам