Ошибка сегментации при записи в массив строк - PullRequest
0 голосов
/ 25 января 2020

Я пытаюсь скопировать некоторые аргументы, переданные в argv, в массив строк. Вот моя программа.

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

int main (int argc, char * argv[]) {
    char **args = malloc(argc * sizeof(char *));
    for (int i = 0; i < argc - 1; ++i) {
        strcpy(*(args+i), argv[i+1]);
    }
}

Я получаю ошибку сегментации в for l oop. Почему это происходит?

Ответы [ 3 ]

5 голосов
/ 25 января 2020

Вы получаете ошибку сегментации, потому что используете неинициализированные указатели.

Другими словами: *(args+i) неинициализирован.

Давайте посмотрим на вашу память:

char **args = malloc(argc * sizeof(char *));

Это даст локальную переменную args, которая указывает на динамически выделенную область памяти c, состоящую из argc указателей на char. Выглядит так:

enter image description here

Но указатели на argc на символ не инициализированы (т.е. malloc ничего не инициализирует), поэтому реальная картина это:

enter image description here

То есть - argc указатели на char могут указывать куда угодно.

Поэтому, когда вы делаете

strcpy(*(args+i), argv[i+1]);
       ^^^^^^^^^
       Read uninitialized pointer

Вы читаете i-й неинициализированный указатель и копируете строку в argv[i+1] в это место. Другими словами - в место, которое мы не можем знать, где находится и которое больше всего нравится, не принадлежит вашей программе. Это может привести к ошибке сегмента.

Поэтому, прежде чем копировать что-либо, вы хотите, чтобы эти хар-указатели указывали на некоторые символы. Как:

enter image description here

Так что в основном вам нужно сделать дополнительные malloc.

Теперь одна проблема: сколько у вас символов нужно malloc?

Ну, вы не можете знать, пока не узнаете длину входных строк. Поэтому вам нужно поместить malloc внутрь l oop. Как:

int main (int argc, char * argv[]) {
    char **args = malloc(argc * sizeof(char *));
    for (int i = 0; i < argc - 1; ++i) {
        *(args+i) = malloc(strlen(argv[i+1]) + 1);  // Allocate memory
        strcpy(*(args+i), argv[i+1]);
    }
}

Примечание:

  • Вам не нужно писать sizeof(char), как всегда 1

  • Вы должны добавить 1 к длине строки входной строки, чтобы зарезервировать память для завершения строки.

  • Вы должны всегда проверять, что malloc не возвращает NULL

  • Вместо *(args+i) вы можете использовать более читаемую форму args[i]

Таким образом, после реального выполнения картина может быть:

enter image description here

1 голос
/ 25 января 2020

Проблема заключается в этой части вашего кода:

malloc(argc * sizeof(char *));

Не думайте, что sizeof(char*) даст вам размер строки.

Что такое размер указателя?

Решение:

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

{
    char* copyOfArgv;

    copyOfArgv = strdup(argv[1]);
}

strdup () - что он делает в C?

0 голосов
/ 25 января 2020

Проблема в том, что вы выделили память для указателей, а не для строки (аргументы самого argv), следовательно, strcpy недопустим - вызывая segmentation fault.

Было бы лучше просто:

Выделите память для указателей (как вы это сделали), затем сделайте эти указатели указать на переданные аргументы. Пример:

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

 int main (int argc, char * argv[]) {
     char **args = malloc(argc*sizeof(char *)); //allocated memory for the pointers only
     int i=0;

     for(;i<argc;i++)
     {
         args[i]=argv[i];  //making the pointers POINT to the arguments including the 0th argument as well
         i++;
     }
     return 0;
 }

Для использования strcpy вы должны были выделить память для самих аргументов, а затем скопировать их.

...