1

I'm following K & R. At the end of chapter 1, one of the proposed exercises is about writing a text wrapping program. Here's the code I wrote:

#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;
            }
        }
    }
}

I wrote a file called wraptest which includes the following:

asd

asdf
asd fg

asdflkjasdad sasdf
adsfa asdfasfd adfsdf
asd asdfadfasdfad
this line

when running

./wrap < wraptest

I get the following

asd

asdf
asd fg

asdflkjasdad
sasdf
adsfa
asdfasfd

asd
asdfadfasdfad
Segmentation fault (core dumped)

Valgrind gives me the following:

==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)

So what's the error? I've been searching for about an hour but I haven't found it.

4

1 回答 1

1

You're never checking the value of i, yet it is indexing into your string array in the wrap function. Here is where the i value grows into the 1000's on my machine before crashing. I would recommend putting it on a debugger, simplifying your code, or at least check the variable that indexes into your string buffer to ensure it is not past the end of the buffer. HTH!

EDIT

Since you asked, I'll show you how I debugged this, just a little, on Ubuntu 12.04 LTS.

From the shell, file called sotest.c

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

You'll see:

GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04 Copyright (C) 2012 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i686-linux-gnu". For bug reporting instructions, please see: http://bugs.launchpad.net/gdb-linaro/... Reading symbols from /home/macduff/sotest...done. (gdb)

Then, invoke the program with the input file:

run < wraptest

Then you'll get some output text with the stack trace

Program received signal SIGSEGV, Segmentation fault. 0x08048666 in wrap ( s=0xbfffebd4 "asd\n\030\313\375\267\254|\376\267\f\356\377\277", l=3) at sotest.c:58 58 for (i = c + WRAP - 1; i >= c && s[i] != ' ' && s[i] != '\t'; --i)

于 2013-06-29T01:27:04.833 回答