简体   繁体   中英

Kernighan and Ritchie Exercise 2-2 Debugging?

I am working through K&R (2nd edition) for my own edification and encountered the following exercise (exercise 2-2 p42):

Write a loop equivalent to the following without using && or ||:

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

This was my solution:

#include <stdio.h>

/* write a loop equivalent to the following without using && or ||

   for (i=0; i<lim-1 && (c=getchar()) != '\n' && c != EOF; ++i)
           s[i] = c;
*/

int main()
{
    int counter = 0, lim = 1000;
    int s[lim], c;

    while(counter < lim-1)
    {
        while((c = getchar()) != '\n')
        {
            while(c != EOF)
            {
                s[counter] = c;
            }
        }
        counter++;
    }   
    return 0;
}

I was expecting the indented loops and therefore the entire program to exit normally once it encountered a newline character ( '\\n' ) or an EOF character ( Ctrl-d on my Linux machine), but to my surprise it happily soldiers on. I tried to debug it using gdb but still could not figure it out.

What am I not seeing?

Addendum: I tried to reverse the sequence of tests the while loops perform and added an if statement to break out of the outer loop if c == '\\n' but am still not seeing it! I am also having difficulty trying to run GDB entering text into the command line and simultaneously printing the value of c , even when I tried to link gdb to the pid of a running copy of the executable. I realize that there are probably other ways to solve this exercise, eg setting an OK_TO_EXECUTE flag or variable that is true only if all three conditions are met, but I am bothered by the fact that I seem unable to find the bug in a seemingly simple program. This is precisely why I am returning to K&R to go through the book more thoroughly and to solve the exercises properly.

Redone code (still buggy!!!):

#include <stdio.h>

/* write a loop equivalent to the following without using && or ||

   for (i=0; i<lim-1 && (c=getchar()) != '\n' && c != EOF; ++i)
           s[i] = c;
*/

int main()
{
    int counter = 0, lim = 1000;
    int s[lim], c;



    while((c = getchar()) != EOF)
    { 
        if ( c == '\n')
            break;

        while(c != '\n')
        {
            while(counter < lim-1)
            {
                s[counter] = c;
                counter++;
            }
        }
    }   
    return 0;
}

SOLVED! - I think! I think I have finally figured it out. The inner loops as written in my redone solution will still loop endlessly or at lease till lim is reached. I added break statements and think I am on my way to a solution.

I am still wrestling with how to run gdb on this problem though; enter the command line entries AND print the value of c . Linking gdb to the pid of the executable still did not work as expected. I even posted a separate question regarding gdb.

but to my surprise it happily soldiers on

You have three nested loops. A newline would terminate one of the inner loops, while the outermost loop would happily carry on (until you've hit Enter lim times).

I can give you a hint: you probably shouldn't be using nested loops for this.

You have added loops that didn't exist in the original ... that's conceptually and logically wrong. The most obvious solution uses break :

for (i = 0; i < lim-1; ++i)
{
    c = getchar();
    if (c == '\n')
        break;
    if (c == EOF)
        break;

    s[i] = c;
}

Or if you're pretending that C doesn't have break , you can do something like this (this is not exactly equivalent because i doesn't have the same value if '\\n' or EOF is encountered):

for (i = 0; i < lim-1;)
{
    c = getchar();
    if (c == '\n')
        i = lim-1;
    else if (c == EOF)
        i = lim-1;
    else
        s[i++] = c;
}

Or you can use the Pascal approach:

#include <stdbool.h>
...
i = 0;
bool more = i < lim-1;

while (more)
{
    c = getchar();
    if (c == '\n')
        more = false;
    else if (c == EOF)
        more = false;
    else
    {
        s[i++] = c;
        more = i < lim-1;
    }
}

With goto

i=0;
loop:
if( i >= lim - 1) goto end;
c = getchar();
if(c == '\n') goto end;
if(c == EOF) goto end;
s[i++] = c;
goto loop;
end:

Without break , goto and with just one for , still without && and || .

for (i=0; i < lim - 1 ? ((c=getchar()) == '\n' | c == EOF) == 0 : 0; ++i)
  s[i] = c;

Update

As noted by @Jim it's way better to set order of execution explicitly by using internal ?:

for (i=0; i >= lim - 1 ? 0 : (c=getchar()) == '\n' ? 0 : c != EOF; ++i)
  s[i] = c;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM