Ошибка сегментации при печати гистограммы

Хорошо, поэтому я хотел задать этот вопрос: «Напишите программу для печати гистограммы длин слов на входе» (упражнение 1-13 из книги C-программирования Брайана и Денниса Ричи). В этом коде я печатаю только количество слов разной длины (это моя первая попытка).

Эта программа компилируется нормально, но при запуске кода я получаю эту ошибку Segmentation fault (дамп кода). Что не так с этим кодом?

#include<stdio.h>
void read(char input[]);
void draw(int i[]);
main()
{
    int i,k,l;
    int len[16];
    char input[100];
    read(input);
    i=k=l=0;
    for(l=0;l<=15;l++)
    {
        len[l]=0;
    }
    while(input[i]!='/0')
    {   
        if(input[i]!='\n'&&input[i]!='\t'&&input[i]!=' ')
        {   k++;
            i++;
        }
        else
        {   len[k]=len[k]+1;
            k=0;
            i++;    
        }
    }
    draw(len);
    return 0;
}

void read(char c[])
{
    int i=0;
    int a;
    while((a=getchar())!=EOF)
    {   c[i]=a;
        i++;
    }
    c[i]='\0';
}

void draw(int len[])
{   int i=0;
    printf("Length\tWords\n");
    for(i=1;i<=15;i++)
    printf("%6d\t%6d\n",i,len[i]);
}

person Vicky    schedule 19.08.2012    source источник
comment
Возможно, вы захотите использовать отладчик и, по крайней мере, дать нам больше информации о коде ошибки: o   -  person xQuare    schedule 19.08.2012
comment
@Papergay Извините, я немного новичок в c, как мне это сделать? Я просто работаю над linux-терминалом.   -  person Vicky    schedule 19.08.2012
comment
Выполните поиск в Google, например. учебник gdb.   -  person Some programmer dude    schedule 19.08.2012
comment
Не имеет отношения к вашей проблеме, но вы можете не использовать имя read для своей собственной функции. В системе уже есть функция с таким названием.   -  person Some programmer dude    schedule 19.08.2012
comment
Возьмите это! И это. И это, это, это и это.   -  person xQuare    schedule 19.08.2012
comment
@Papergay Вот результаты. Программа получила сигнал SIGSEGV, ошибка сегментации. 0x080484f2 в main() at Histogram.c:22 22 { len[k]=len[k]+1;   -  person Vicky    schedule 19.08.2012
comment
Выполните print k, чтобы узнать, какое значение имеет переменная k.   -  person Some programmer dude    schedule 19.08.2012


Ответы (4)


for(l=0;l<=15;l++)
{
    len[l]=0;
}

Ваш массив имеет типint [15], поэтому вы обращаетесь к элементу вне массива.

У вас точно такая же проблема в функции draw здесь:

for(i=1;i<=15;i++)

Также:

char a;
while((a=getchar())!=EOF)

a должен быть типа int, а не char. Смотрите это для объяснения:

http://c-faq.com/stdio/getcharc.html

person ouah    schedule 19.08.2012
comment
Вы правы, просто изменили код на int[16], но проблема осталась. - person Vicky; 19.08.2012
comment
@Vicky также смотрите вторую часть ответа - person ouah; 19.08.2012
comment
Сделал все, что вы сказали, все равно та же ошибка. Спасибо, в любом случае попробую отладить - person Vicky; 19.08.2012

одна ошибка, которую я мог заметить, находится в for(l=0;l<=15;l++). должно быть for(l=0;l<15;l++).

int len[15] означает, что len представляет собой массив целых чисел размером 15 с допустимыми местоположениями как len[0], len[1], ... len[14], но здесь вы получаете доступ к len[15], который равен undefined, и может вызвать segmentation fault.

person Eight    schedule 19.08.2012

Эта строка содержит ошибку:

while(input[i]!='/0')

и заставляет ваш код обращаться к памяти, не принадлежащей вашей программе.

Так должно быть:

while(input[i]!='\0')

поскольку завершающий символ строки равен '\ 0'.

person harpun    schedule 19.08.2012
comment
Мужик ты золотой. Извините, не видел ваш комментарий раньше. Я имею в виду, что он работает сейчас, ура. - person Vicky; 19.08.2012

В функции read вы не проверяете длину ввода, поэтому, если ваш ввод больше, чем количество записей в c, вы будете писать в не принадлежащую вам память.

Изменить:

После того, как вы проверили в отладчике, искать причину ошибки стало проще, и если вы посмотрите на этот цикл while, то увидите это совершенно ясно:

while(input[i]!='/0')

Вы сравниваете символ в input с недопустимым символьным литералом. Вы используете прямую косую черту, но это должна быть обратная косая черта: '\0'. На самом деле, вы должны дать предупреждение о многосимвольном символьном литерале.

person Some programmer dude    schedule 19.08.2012
comment
Но я набираю всего около 4 слов во время выполнения, так что все должно быть в порядке, не так ли? - person Vicky; 19.08.2012
comment
@Vicky Пока в этих словах меньше 99 символов. - person Some programmer dude; 19.08.2012
comment
@Vicky Обновил мой ответ (теперь) очевидным ответом. - person Some programmer dude; 19.08.2012
comment
Спасибо, да, это предупредило. В чем разница между '\0' и '/0' - person Vicky; 19.08.2012
comment
@Vicky '\0' — это одиночный символ, так называемый NULL-терминатор, который используется для завершения строк (как вы, очевидно, уже знаете). '/0' — это два разных символа, и в символьном литерале это не совсем допустимо. - person Some programmer dude; 19.08.2012