Выполнение printf () и Ошибка сегментации - PullRequest
18 голосов
/ 27 февраля 2012
#include<stdio.h>

int main()
{
    char *name = "Vikram";
    printf("%s",name);
    name[1]='s';
    printf("%s",name);
    return 0;
}

На терминале не выводится выходной сигнал, просто возникает ошибка сегментации.Но когда я запускаю его в GDB, я получаю следующее:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400525 in main () at seg2.c:7
7       name[1]='s';
(gdb) 

Это означает, что программа получает ошибку SEG на 7-й строке (очевидно, я не могу писать в массиве константных символов).Тогда почему printf () строки № 6 не выполняется?

Ответы [ 4 ]

39 голосов
/ 27 февраля 2012

Это связано с потоковой буферизацией stdout. Если вы не наберете fflush(stdout) или не напечатаете новую строку "\n", вывод может быть буферизован.

В этом случае происходит сбой, прежде чем буфер будет очищен и напечатан.

Вы можете попробовать это вместо:

printf("%s",name);
fflush(stdout);        //  Flush the stream.
name[1]='s';           //  Segfault here (undefined behavior)

или

printf("%s\n",name);   //  Flush the stream with '\n'
name[1]='s';           //  Segfault here (undefined behavior)
10 голосов
/ 27 февраля 2012

Сначала вы должны завершить свои printfs "\ n" (или хотя бы последним).Но это не относится к segfault.

Когда компилятор компилирует ваш код, он разбивает двоичный файл на несколько частей.Некоторые из них доступны только для чтения, а другие - для записи.Запись в раздел только для чтения может стать причиной ошибки.Строковые литералы обычно помещаются в раздел только для чтения (gcc должен поместить его в «.rodata»).Имя указателя указывает на этот раздел ro.Поэтому вы должны использовать

const char *name = "Vikram";

В своем ответе я использовал несколько слов "может", "должен".Поведение зависит от вашей ОС, параметров компилятора и компиляции (сценарий компоновщика определяет разделы).

При добавлении

-Wa,-ahlms=myfile.lst

в командную строку gcc создается файл myfile.lst с сгенерированнымассемблерный код.Вверху вы можете увидеть

    .section .rodata
.LC0:
    .string "Vikram"

, который показывает, что строка находится в Vikram.

Тот же код, использующий (должен быть в глобальной области видимости, иначе gcc может сохранить его в стекеобратите внимание, что это массив, а не указатель)

char name[] = "Vikram";

производит

    .data
    .type name, @object
    .size name, 7
name:
    .string "Vikram"

Синтаксис немного отличается, но посмотрите, как он сейчас находится в разделе .data, который читаетсянаписать.Кстати, этот пример работает.

5 голосов
/ 27 февраля 2012

Причина, по которой вы получаете ошибку сегментации, состоит в том, что строковые литералы C читаются только в соответствии со стандартом C, и вы пытаетесь написать 's' над вторым элементом массива литералов "Vikram".

Причина, по которой вы не получаете выходных данных, заключается в том, что ваша программа буферизует свои выходные данные и вылетает, прежде чем она имеет возможность очистить свой буфер. Цель библиотеки stdio, в дополнение к предоставлению дружественных функций форматирования, таких как printf (3), состоит в том, чтобы уменьшить накладные расходы на операции ввода-вывода, буферизуя данные в буферах в памяти и только сбрасывая вывод при необходимости, и выполняя ввод только изредка вместо постоянно. Фактический ввод и вывод в общем случае не будут происходить в тот момент, когда вы вызываете функцию stdio, но только когда буфер вывода заполнен (или буфер ввода пуст).

Ситуация немного отличается, если объект FILE установлен, поэтому он постоянно мигает (например, stderr), но в целом это суть.

Если вы выполняете отладку, лучше всего выполнить fprintf для stderr, чтобы убедиться, что ваши отладочные распечатки будут сброшены перед сбоем.

1 голос
/ 27 февраля 2012

По умолчанию, когда stdout подключен к терминалу, поток буферизуется в строке.На практике в вашем примере отсутствие '\n' (или явного сброса потока) является причиной того, что вы не печатаете символы.

Но в теории неопределенное поведение не ограничено (из Стандарта «поведение [...], для которого настоящий международный стандарт не предъявляет никаких требований» * ), и ошибка может произойти даже до того, как произойдет неопределенное поведение, например, перед первым printf вызовом!

...