Программа для переноса текста в c работает некорректно

Я слежу за K & R. В конце главы 1 одно из предложенных упражнений касается написания программы переноса текста. Вот код, который я написал:

#include <stdio.h>
#define MAXLINE 1000
#define WRAP 10

int getl(char s[]);
void wrap(char s[], int l);

/* wrap.c: wraps text */
main ()
{
    char line[MAXLINE];
    int c;

    while ((c = getl(line)) >= 0)
        wrap(line, c);
    return 0;
}

int getl(char s[])
{
    int i, c;

    for (i = 0; (c = getchar()) != '\n' && c != EOF && i < MAXLINE; ++i)
        s[i] = c;
    s[i] = '\n';
    if (c == EOF)
        i = -1;
    return i;
}

void wrap(char s[], int l)
{
    int i = 1,ii, c;

    if (l == 0)
        putchar('\n');
    for(c = 0; s[i-1] != '\n'; c = c + i)
    {
        if (l - c <= WRAP)
            for (i = c; i <= l; ++i)
                putchar(s[i]);
        else
        {
            for (i = c + WRAP - 1; i >= c && s[i] != ' ' && s[i] != '\t'; --i)
                ;
            if (i == (c-1))
            {
                for (i = c + WRAP; s[i] != ' ' && s[i] != '\t' && s[i] != '\n'; ++i)
                    ;
                for (ii = c; ii < i; ++ii)
                    putchar(s[ii]);
                putchar('\n');
                if (s[i] != '\n')
                    ++i;
            }
            else if (i == c)
                ++i;
            else
            {
                for (ii = c; ii < i; ++ii)
                    putchar(s[ii]);
                putchar('\n');
                ++i;
            }
        }
    }
}

Я написал файл с именем Wraptest, который включает в себя следующее:

asd

asdf
asd fg

asdflkjasdad sasdf
adsfa asdfasfd adfsdf
asd asdfadfasdfad
this line

при беге

./wrap < wraptest

Я получаю следующее

asd

asdf
asd fg

asdflkjasdad
sasdf
adsfa
asdfasfd

asd
asdfadfasdfad
Segmentation fault (core dumped)

Вальгринд дает мне следующее:

==6729== Conditional jump or move depends on uninitialised value(s)
==6729==    at 0x80486EE: wrap (wrap.c:37)
==6729==    by 0x80484CC: main (wrap.c:15)
==6729==  Uninitialised value was created by a stack allocation  
==6729==    at 0x80484A2: main (wrap.c:10)
==6729== 
==6729== Invalid read of size 1 
==6729==    at 0x80486E9: wrap (wrap.c:37)
==6729==    by 0x80484CC: main (wrap.c:15)
==6729==  Address 0xbe8a3623 is not stack'd, malloc'd or (recently) free'd
==6729== 
==6729== 
==6729== Process terminating with default action of signal 11 (SIGSEGV)
==6729==  Access not within mapped region at address 0xBE8A3623
==6729==    at 0x80486E9: wrap (wrap.c:37)
==6729==    by 0x80484CC: main (wrap.c:15)
==6729==  If you believe this happened as a result of a stack
==6729==  overflow in your program's main thread (unlikely but
==6729==  possible), you can try to increase the size of the
==6729==  main thread stack using the --main-stacksize= flag.
==6729==  The main thread stack size used in this run was 8388608.
==6729== 
==6729== HEAP SUMMARY:
==6729==     in use at exit: 0 bytes in 0 blocks
==6729==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==6729== 
==6729== All heap blocks were freed -- no leaks are possible
==6729== 
==6729== For counts of detected and suppressed errors, rerun with: -v
==6729== ERROR SUMMARY: 6 errors from 2 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

Так в чем же ошибка? Я искал около часа, но я не нашел его.

1 ответ

Решение

Вы никогда не проверяете ценность i все же он индексирует в ваш строковый массив в wrap функция. Вот где i ценность вырастает до 1000-х на моей машине до сбоя. Я бы порекомендовал поместить его в отладчик, упростить ваш код или хотя бы проверить переменную, которая индексирует ваш строковый буфер, чтобы убедиться, что он не находится за концом буфера. НТН!

РЕДАКТИРОВАТЬ

Так как вы спросили, я покажу вам, как я немного отладил это на Ubuntu 12.04 LTS.

Из оболочки файл называется sotest.c

# use the -g for debug info
gcc -g sotest.c -o sotest
# invoke the gnu debugger
gdb sotest

Вот увидишь:

GNU gdb (Ubuntu / Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04 Copyright (C) 2012 Free Software Foundation, Inc. Лицензия GPLv3+: GNU GPL версии 3 или более поздней версии http://gnu.org/licenses/gpl.html Это бесплатное программное обеспечение: вы можете изменять и распространять его. НЕ ПРЕДОСТАВЛЯЕТСЯ ГАРАНТИИ, если это разрешено законом. Введите "показать копирование" и "показать гарантию" для деталей. Эта GDB была настроена как "i686-linux-gnu". Инструкции по сообщению об ошибках см. По адресу: http://bugs.launchpad.net/gdb-linaro/... Чтение символов из /home/macduff/sotest...done. (GDB)

Затем вызовите программу с входным файлом:

run < wraptest

Тогда вы получите некоторый выходной текст с трассировкой стека

Программа получила сигнал SIGSEGV, Ошибка сегментации. 0x08048666 в обертке ( s=0xbfffebd4 "asd\n\030\313\375\267\254|\376\267\f\356\377\277", l=3) в sotest.c:58 58 для (i = c + WRAP - 1; i >= c && s[i]!= ' ' && s[i]!= '\t'; --i)

Другие вопросы по тегам