Я не знаю, почему я получаю ошибку сегментации в моем коде - PullRequest
0 голосов
/ 01 марта 2019

В коде я пытаюсь прочитать файл, затем делю его на strtok, чтобы получить идентификатор каталога (из 8 символов) и тип файла, который я хочу передать в каталог (A, B, C.PDF).Затем я использую систему функций для выполнения соответствующей команды.Я знаю, что в текстовом файле он идет первым идентификатором каталога после типа файла.У меня нет проблем с компиляцией, но когда я запускаю программу, я получаю ошибку сегментации и не знаю почему.

#include <stdio.h>
#include <stdlib.h>
#define _GNU_SOURCE
#include <unistd.h>
#include <ctype.h>
#include <stdbool.h>
#include <string.h>


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

    char ch, str[999], id[8], command[25];
    FILE *fp;
    int i = 0;
    char *pch;

    fp = fopen("p1.text", "r");

    if (fp == NULL)
    {
        perror("Error while opening the file.\n");
        exit(EXIT_FAILURE);
    }

    while((ch = fgetc(fp)) != EOF){

        str[i] = ch;    
        i++;

    }
    pch = strtok(str, " ,.-\n");

    while(pch != NULL){
        if(isalpha(pch)){
            sprintf(command, "cp %s.pdf %s", pch, id);
            system(command);
            strcpy(command, "");
        }
        if(strlen(pch) == 8){
            strcpy(id, pch);
        }
        pch = strtok(NULL, " ,.-\n");
    }

    fclose(fp);

    return 0;
}

Ответы [ 2 ]

0 голосов
/ 01 марта 2019

Я собираюсь показать вам процесс отладки, который вы должны изучить, чтобы вы могли решить эти проблемы самостоятельно.Шаги, которые я предпринял, показаны ниже.Имейте в виду, что я не пытаюсь исправить все возможные проблемы с вашим кодом.Я только что изолировал и исправил первоначальную проблему.

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

Я запустил ваш код с valgrind, и он дал мне следующий вывод:

Перед запуском valgrindВы должны построить свой исполняемый файл с отладочными символами.Предполагая, что gcc вы можете выполнить следующие шаги:

jnorton@ubuntu:~/source$ gcc -ggdb fault.c 
jnorton@ubuntu:~/source$ ./a.out 
pch = this
Segmentation fault (core dumped)
jnorton@ubuntu:~/source$ clear

jnorton@ubuntu:~/source$ gcc -ggdb fault.c 
jnorton@ubuntu:~/source$ valgrind --leak-check=yes ./a.out
==6745== Memcheck, a memory error detector
==6745== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==6745== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==6745== Command: ./a.out
==6745== 
pch = this
==6745== Invalid read of size 2
==6745==    at 0x108B25: main (fault.c:35)
==6745==  Address 0x2fda2c0 is not stack'd, malloc'd or (recently) free'd
==6745== 
==6745== 
==6745== Process terminating with default action of signal 11 (SIGSEGV)
==6745==  Access not within mapped region at address 0x2FDA2C0
==6745==    at 0x108B25: main (fault.c:35)
==6745==  If you believe this happened as a result of a stack
==6745==  overflow in your program's main thread (unlikely but
==6745==  possible), you can try to increase the size of the
==6745==  main thread stack using the --main-stacksize= flag.
==6745==  The main thread stack size used in this run was 8388608.
==6745== 
==6745== HEAP SUMMARY:
==6745==     in use at exit: 552 bytes in 1 blocks
==6745==   total heap usage: 3 allocs, 2 frees, 5,672 bytes allocated
==6745== 
==6745== LEAK SUMMARY:
==6745==    definitely lost: 0 bytes in 0 blocks
==6745==    indirectly lost: 0 bytes in 0 blocks
==6745==      possibly lost: 0 bytes in 0 blocks
==6745==    still reachable: 552 bytes in 1 blocks
==6745==         suppressed: 0 bytes in 0 blocks
==6745== Reachable blocks (those to which a pointer was found) are not shown.
==6745== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==6745== 
==6745== For counts of detected and suppressed errors, rerun with: -v
==6745== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
jnorton@ubuntu:~/source$ 

Уведомление valgrind сообщил:

==6745==    at 0x108B25: main (fault.c:35)

Я добавил несколько отладочных printfs, но строка 35:

if(isalpha(pch)){

Здесь происходит segfault, потому что isalpha() принимает аргумент int, а не указатель на строку.Изменение этой строки на следующее останавливает segfault:

if(isalpha((int)pch[0])){

Теперь, это только одна проблема в вашем коде.У вас может есть другие проблемы.

0 голосов
/ 01 марта 2019

Переменная id недостаточно велика для хранения значения, необходимого для хранения.

Строки в C заканчиваются нулем.Таким образом, строка из 8 символов требует 9 байтов памяти.id имеет длину всего 8 элементов, поэтому при копировании в него вы пишете после конца массива.Запись вне границ массива вызывает неопределенное поведение , которое в этом случае проявляется в крахе вашего кода.

Создайте id 9 элементов длиной вместо 8:

int id[9];

Вы также неправильно сохраняете результат fgetc.Вы объявляете ch как char, но fgetc возвращает int.Это необходимо, чтобы отличить EOF от обычного значения символа.Так что измените тип ch на int.

Кроме того, вы делаете вещи немного сложнее, чем нужно, читая весь файл сразу, а затем имея внутренний конечный автомат в вашемцикл, который вызывает strtok, чтобы выяснить, какой элемент вы читаете.

Вы можете упростить это, читая строку за раз с fgets, затем вызывая strtok один раз, чтобы получить idи еще раз, чтобы получить pch:

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

int main()
{
    char line[100], command[100];
    FILE *fp;
    char *pch, *id;

    fp = fopen("p1.text", "r");

    if (fp == NULL)
    {
        perror("Error while opening the file.\n");
        exit(EXIT_FAILURE);
    }

    while (fgets(line, sizeof(line), fp)) {
        id = strtok(line, " \n");
        if (!id) continue;

        pch = strtok(NULL, " \n");
        if (!pch) continue;

        snprintf(command, sizeof(command), "cp %s.pdf %s", pch, id);
        //printf("command=%s\n", command);
        system(command);
    }

    fclose(fp);

    return 0;
}
...