Я пытаюсь реализовать пользовательскую оболочку в «режиме пакетного файла». Допустим, у меня есть файл с именем «batchfile», содержащий:
ls –l
pwd
ps
touch hello
ls -l ; cat file ; grep foo file2
ls -l && cat file
quit
Вызывая ./myShell batchfile, я хочу выполнять команды отдельно. Но когда я пытаюсь прочитать строки из файла с помощью fgets(), а затем сохранить их в массив (char * batch_cmds[512]), я получаю:
Segmentation fault (core dumped)
Это мой код до сих пор:
int main(int argc, char *argv[]){
if (argc >=2){
char str[512];
char *batch_cmds[512];
int i=0;
FILE *fp;
fp = fopen(argv[1], "r");
while(fgets(str,512, fp)!=NULL){
strcpy(batch_cmds[i], str);
i++;
}
fclose(fp);
Я не могу понять, почему эта ошибка выскакивает.
C использует старый стиль управления памятью стека/кучи, поэтому вам нужно будет прочитать, как работают указатели и malloc.
@ChrisTurner прав, batch_cmds - это указатель ни на что, вам нужно управлять памятью или статически выделять ее, я бы предложил использовать связанный список и выделять каждый узел, когда вы успешно читаете строку.





Вы зарезервировали место для самих указателей, но не для каждой строки, на которую должен указывать каждый такой указатель. Каждый batch_cmds[i] указывает «куда-то», по крайней мере, не на выделенный вами объект; когда вы затем вызываете strcpy(batch_cmds[i], str);, вы записываете содержимое str «куда-то» и создаете неопределенное поведение (например, сбой; на самом деле оператор batch_cmds[i] обращается к неинициализированному массиву и сам по себе уже является неопределенным поведением; но это само по себе редко приводит к сбою).
Вместо
strcpy(batch_cmds[i], str);
написать
batch_cmds[i] = strdup(str);
Команда strdup выполняет и то, и другое: (1) резервирование памяти, достаточной для хранения содержимого str, и (2) затем копирование содержимого str. Это эквивалентно batch_cmds[i] = malloc(strlen(str)+1); strcpy(batch_cmds[i], str));.
Кроме того, убедитесь, что i — это <512, чтобы batch_cmds[i] не превышала границы массива.
Огромное спасибо. Не мог бы объяснить это лучше. Это сработало отлично.
Линия:
char *batch_cmds[512];
Объявляет массив из 512 указателей на char, но эти указатели не инициализированы (дикие, висящие, выбирайте сами).
Ваши варианты:
Объявите двумерный массив в стеке:
char batch_cmds[512][512];
Используйте динамическое управление памятью для выделения строк в куче:
char *batch_cmds[512];
int i;
for(i = 0; i < 512; i++)
{
batch_cmds[i] = malloc(string_length);
if (batch_cmds[i] == NULL)
{
// handle alloc error
}
}
// Code that uses batch_cmds...
for(i = 0; i < 512; i++)
{
free(batch_cmds[i]);
batch_cmds[i] = NULL;
}
Используйте strdup для назначения указателям на char в batch_cmds (продемонстрировано в ответе Стефана Лехнера). Обратите внимание, что strdup также использует динамическую память за кулисами, поэтому возвращаемые указатели также должны быть переданы на free, когда вы закончите с ними, чтобы избежать утечек памяти.
вы не выделяете память для
batch_cmds, поэтому (например)batch_cmds[0]не указывает на допустимое место в памяти для хранения строки