1

I'm doing the exercises from C Programming Language, the one where you need to make a function to reverse a line. So I did and it works sometimes. But only some times. With the same test it gives different results. I really don't get it, and would appreciate some help. 3 tries out of 4 it would print around 150 spaces and 1 out of 4 it would print the reversed line just like I wanted, though with some junk in the end for some reason. I was thinking of doing it with pointers, but couldn't figure them out as of now. Here's my code:

#include <stdio.h>

void reverse(char theline[150]){
    int i, j;
    char tmp[150];
    for (i = 0; theline[i] != 0; i++){
        tmp[i] = theline[i];
    }
    for (j = 0; i >= 0; j++){
        theline[j] = tmp[i];
        i--;
    }
}

int main() {
    char line[150];
    char c;
    int counter = 0;
    do {
        counter = 0;
        while (((c = getchar()) != '\n') && (c != EOF)) { //one line loop
            line[counter] = c;
            counter++;
        }
        if (counter > 80){
            reverse(line);
            printf("%s\n", line);
        }
    } 
    while (c != EOF);

    return 0;
}

I compile it with "gcc -g -Wall program -o test" and the compiler doesn't give me any errors or warnings. My OS is Ubuntu and I test it with "./test < longtext.txt". This text file has a few lines of different length.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 1
    `EOF` will not fit into `char c;` You need to declare `int c;`... – Fe2O3 Sep 03 '22 at 10:32
  • What do you mean? It works as intended as it exits the main loop when the end of file is achieved. – MemoryDreams Sep 07 '22 at 14:14
  • https://stackoverflow.com/a/10720881/17592432 "It works" because the '\n' from stdin breaks the loop. If input redirected to come from a file, it may not work so well (depending on your compiler)... EOF is not a `char` and that is why `getchar()` returns an `int`, not a `char`... – Fe2O3 Sep 07 '22 at 21:18

2 Answers2

2

After this loop

    while (((c = getchar()) != '\n') && (c != EOF)) { //one line loop
        line[counter] = c;
        counter++;
    }

the character array line does not contain a string because the stored characters are not appended with the terminating zero character '\0'.

So this loop within the function

for (i = 0; theline[i] != 0; i++){
    tmp[i] = theline[i];
}

invokes undefined behavior.

You need to append the array with the terminating zero character '\0'.

But even if the passed character array will containe a string the second for loop

for (i = 0; theline[i] != 0; i++){
    tmp[i] = theline[i];
}
for (j = 0; i >= 0; j++){
    theline[j] = tmp[i];
    i--;
}

writes the terminating zero character '\0' in the first position if the array theline. As a result you will get an empty string.

Also the function shall not use the magic number 150 and an auxiliary array.

Pay attention to that the variable c should be declared as having the type int. In general the type char can behave either as the type signed char or unsigned char depending on compiler options. If it will behave as the type unsigned char then this condition

c != EOF

will always evaluate to true.

Without using standard C string functions the function can be declared and defined the following way

char * reverse( char theline[] )
{
    size_t i = 0;

    while ( theline[i] != '\0' ) i++;

    size_t j = 0;

    while ( j < i )
    {
        char c = theline[j];
        theline[j++] = theline[--i];
        theline[i] = c;
    }

    return theline;
}

Here is a demonstration program

#include <stdio.h>

char * reverse( char theline[] )
{
    size_t i = 0;

    while ( theline[i] != '\0' ) i++;

    size_t j = 0;

    while ( j < i )
    {
        char c = theline[j];
        theline[j++] = theline[--i];
        theline[i] = c;
    }

    return theline;
}

int main( void ) 
{
    char s[] = "Hello World!";

    puts( s );
    puts( reverse( s ) );
}

The program output is

Hello World!
!dlroW olleH
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

Why muck-around with reversing a buffer when you can simply store-up the entered characters as they arrive.

#include <stdio.h>

int main() {

    for( ;; ) {
        char line[ 150 ];
        int c, counter = sizeof line;

        line[ --counter ] = '\0';

        // NB: EOF is an int, not a char
        while( ( c = getchar() ) != '\n' && c != EOF && counter > 0 )
            line[ --counter ] = (char)c;

        printf( "%s\n\n", line + counter );
        counter = sizeof line;
    }

    return 0;
}

Output:

the quick
kciuq eht

Once upon a time in a land far awy
ywa raf dnal a ni emit a nopu ecnO

I wish I was what I was when I wished I was what I am now.
.won ma I tahw saw I dehsiw I nehw saw I tahw saw I hsiw I
Fe2O3
  • 6,077
  • 2
  • 4
  • 20
  • 1
    The program does not reverse a string. It just outputs entered characters in the reverse order. – Vlad from Moscow Sep 03 '22 at 10:56
  • @VladfromMoscow The "string" is in the stdin character buffer, and is being "reversed" as the characters are pulled out of that buffer by `getchar()`... This certainly IS reversing a string... – Fe2O3 Sep 03 '22 at 10:58
  • 1
    You are mistaking. For example reverse the string char s[] = "Hello"; At first output it as is and then reverse it and output. And then again reverse and output it. – Vlad from Moscow Sep 03 '22 at 11:00
  • @VladfromMoscow What you are describing is not the same as the code snippet shown in the OP. Do you want to edit the OP to conform to your set of rules? The OP attempts to "buffer up" the incoming characters, and then reverse that array. My answer here skips a step and does what appears to be wanted by the OP... Yes, I could, as you have done, buffer the input and THEN reverse it. The effect is the same... – Fe2O3 Sep 03 '22 at 11:03
  • 1
    Actually it is the same. He has a function to which he passes a string. And the function reverses the string. As for your code then you just output entered characters in the reverse order. You do not have a source string to be reversed. – Vlad from Moscow Sep 03 '22 at 11:05
  • @VladfromMoscow Just proves the old adage, "There are many ways to skin a cat"... You've got the accepted answer. My answer is equally valid, just a bit more "directed toward the objective" than mucking with intervening processing... Programmers really should learn to "Think outside the box", imho... – Fe2O3 Sep 03 '22 at 11:08
  • Thanks for the answer! Though the point of the exercise was specifically to make a function and reverse it. Your solution does look more efficient than reversing a buffer. There's only one point I don't understand. What ``line[ --counter ] = (char)c;`` does? Specifically the (char)c part. – MemoryDreams Sep 07 '22 at 14:13
  • @MemoryDreams `(char)c` makes explicit casting `int c` down to a single byte, The presence of the casting tells the compiler that the programmer is aware of this "shrinkage". It is intentional and deliberate, and no "Warning" need be issued by the compiler. (btw: most I/O used is buffered. This answer just used the source "buffer" being the FILE that is `stdin`...) – Fe2O3 Sep 07 '22 at 21:03