Ошибка сегментации с глобальными указателями

Я пытаюсь определить переменную глобального указателя, которую затем можно действительно установить в основной функции, как показано ниже. Однако я получаю ошибку сегментации каждый раз, когда пытаюсь использовать outputName после этого. Я знаю, что это, вероятно, связано с установкой указателя, равного NULL в начале... любая помощь о том, как я мог бы иметь глобальный указатель, который затем устанавливается в main, была бы очень полезна! Вот часть моего кода, которая дает мне ошибки:

    char* outputName = NULL;

    int isNumber(char number[]){
        int i;
        if (number[0] == '-')
            i = 1;
        
        while(number[i] != '\0'){
            if (!isdigit(number[i]))
                return 0;

            i++;
        }

        return 1;
    }

    void catcher(int signo){
        printf("The program is exiting early");
        remove(outputName);
        exit(1);
    }

    int main(int argc, char *argv[]){
        if (argc != 4){
            fprintf(stderr,"Incorrect number of arguments, must supply three.\n");
            exit(1);
        }

        char* inputName = argv[1];
        outputName = argv[2];
        signal(SIGINT, catcher);
        int result = isNumber(argv[3]);
        
        if (result == 0){
            fprintf(stderr, "Invalid maximum line length, please enter an integer\n");
            exit(1);
        }
        
        int maxChars = (atoi(argv[3])) + 1;
        if ((maxChars-1) < 1){
            fprintf(stderr, "Invalid third maximum line length, please enter an integer greater than zero\                                          
    .\n");
            exit(1);
        }

        FILE* inFile = fopen(inputName, "r");
        if (inFile == NULL){
            fprintf(stderr, "Error while opening %s.\n", inputName);
            exit(1);
        }

        FILE* outFile = fopen(outputName, "w");
        if (outFile == NULL){
            fprintf(stderr, "Error while opening %s.\n", outputName);
            exit(1);
        }                                                                                               
        
        char line[maxChars];
        int done = 0;
        while (!done){
            char *readLine = fgets(line, maxChars, inFile);
            if (readLine == NULL){
                if (errno == 0){
                    done = 1;
                } else {
                    fprintf(stderr, "Error when reading line from input file");
                    exit(1);
                }
            }

            int len = strlen(line);
            if (line[len-1] != '\n'){
                line[len] = '\n';
                line[len+1] = '\0';
                char current = ' ';

                while (current != '\n')
                    current = getc(inFile);
            }

            if (!done){
                fputs(line, outFile);
                if (errno != 0){
                    fprintf(stderr, "Error when writing line to output file");
                    exit(1);
                }
            }
        }

        return 0;
    }

person liverr1818    schedule 07.12.2016    source источник
comment
Сколько аргументов вы передаете main()? Вы выполнили базовую отладку, чтобы увидеть значение argv[2]? Вы проверили argc >= 3 ?   -  person John3136    schedule 07.12.2016
comment
передавая четыре аргумента, yes выполнил всю эту проверку ошибок, чтобы убедиться, что значение are правильное.   -  person liverr1818    schedule 07.12.2016
comment
Итак, если outputName действителен после приведенного выше кода, проблема в другом...   -  person John3136    schedule 07.12.2016
comment
не могли бы вы предоставить полный блок кода? Может быть завершена основная функция и что вы делаете с outputName после этого.   -  person danishansari    schedule 07.12.2016
comment
поэтому можно установить глобальный указатель в NULL, а затем установить этот указатель равным чему-то еще в main и использовать этот указатель в других функциях, а также в main без передачи? Извините, только изучаю C!   -  person liverr1818    schedule 07.12.2016
comment
Это зависит от того, на что вы его настроили. Если вы установите его в локальную переменную, которая выходит за рамки, вы получите неопределенное поведение.   -  person John3136    schedule 07.12.2016
comment
так что, возможно, это связано с установкой outputName = argv [2], поскольку это локально, а затем попытка использовать этот указатель вне основного?   -  person liverr1818    schedule 07.12.2016
comment
Вы должны изучить правильное форматирование C. Или узнайте, как полностью запутать свой код.   -  person MD XF    schedule 07.12.2016
comment
Я скомпилировал ваш код, и он работает как шарм. Вы уверены, что именно этот фрагмент кода вылетит на вашем компьютере?   -  person Joël Hecht    schedule 07.12.2016
comment
Продолжительность argv в main() достаточно велика, поэтому маловероятно, что у вас возникнут проблемы с outputName = argv[2]; — есть способы столкнуться с проблемами, но вы, вероятно, не задавали бы этот вопрос, если бы использовали их (atexit() и т. д.) .   -  person Jonathan Leffler    schedule 07.12.2016
comment
Обратите внимание, что вы должны завершать вывод printf() символом новой строки, если хотите быть уверенным, что он появится; используйте также fflush(stdout);, если хотите большей уверенности. Затем обратите внимание на как избежать использования printf() в обработчике сигнала. Вероятно, вам это сойдет с рук — вряд ли это будет причиной ваших проблем, но поскольку вы не показываете никакого кода после присваивания outputName, трудно понять, что вы делаете. Вы говорите, что используете outputName, но единственное показанное место, где он используется, находится в обработчике сигнала. Вы прерываете его?   -  person Jonathan Leffler    schedule 07.12.2016
comment
@JoëlHecht Я отредактировал свой код, чтобы показать весь мой код ... поверьте, может быть, сейчас это с ошибкой?   -  person liverr1818    schedule 07.12.2016
comment
Я попробовал ваш код, и он вылетает из-за ошибки сегментации в функции isNumber: это потому, что i не инициализируется 0, когда число не начинается со знака -. Я также добавляю строку signal(SIGSEGV, catcher); в ваш код, чтобы перехватывать исключение, и обработчик работает нормально, перехватывая исключение ошибки сегментации.   -  person Joël Hecht    schedule 08.12.2016


Ответы (2)


Может быть, обработчик сигнала вызывается до того, как для outputName будет установлено ненулевое значение, вы можете попробовать установить обработчик сигнала после outputName = argv[2]; в основном ()

person Pras    schedule 07.12.2016

внимательно прочитайте signal(7): так как ваш catcher вызывает printf, которая не является безопасной функцией асинхронного сигнала, ваш код имеет неопределенное поведение. Кроме того, ваша управляющая строка printf не заканчивается на \n, а поскольку stdout буферизуется строкой, вывод не будет выполняться. Предпочитайте sigaction(2) вместо signal и установите свой сигнал обработчик после присвоения outputName.

Глобальные переменные, используемые в обработчиках сигналов, должны быть объявлены volatile. Итак, объявите свой char* volatile outputName; в глобальном масштабе. Тогда у вас может быть такой тест, как if (outputName != NULL) remove(outputName); в обработчике. Обычной практикой является установка некоторого глобального флага volatile sig_atomic_t в обработчике сигнала и проверка этого флага в другом месте.

И ваша программа, скорее всего, не успеет получить какой-либо сигнал. Вы, вероятно, должны завершить свою функцию main с некоторым ожиданием (например, прочитать из stdin или usleep(3) или пауза(2) или опрос(2)....).

Конечно, скомпилируйте свой код со всеми предупреждениями и отладочной информацией (gcc -Wall -g) и используйте отладчик (gdb); Я думаю, что отладчик точки наблюдения должен быть очень полезен для поиска вашей ошибки.

Программа, которую вы показываете, скорее всего, не содержит SEGV. Так что ваша настоящая ошибка, скорее всего, где-то в другом месте.

Возможно, используя strace(1) и/или valgrind также может помочь.

person Basile Starynkevitch    schedule 07.12.2016