s164151
s164151

Reputation: 19

C: Printing from char array produces erroneous characters

Solutions for K. N. King's C Programming: A Modern Approach, 2nd Edition, Chapter 8, Programming Project 14, produces different outputs both correct and incorrect. Examples shown below:

Reversal of sentence: you can't swallow a cage can you?
Reversal of sentence: you can't swallow a cage can you�(�?
Reversal of sentence: you can't swallow a cage can you��x�?
Reversal of sentence: you can't swallow a cage can you�Ց�?

As shown by the example input, correct output should be:

Enter a sentence: you can cage a swallow can't you?
Reversal of sentence: you can't swallow a cage can you?

My own solution and below solution (courtesy of Github user @williamgherman; slightly modified for sake of readability) both produces the different outputs.

#include <stdio.h>

int main(void)
{
    char ch, terminator, sentence[100] = {0};
    int i = 0, j;

    printf("Enter a sentence: ");
    for (i = 0; (ch = getchar()) != '\n' && i < 100; i++) {
        if (ch == '.' || ch == '!' || ch == '?') {
            terminator = ch;
            break;
        }
        sentence[i] = ch;
    }

    printf("Reversal of sentence: ");
    while (i >= 0) {
        while (sentence[--i] != ' ' && i != 0)
            ;
        j = i == 0 ? 0 : i + 1;
        while (sentence[j] != ' ' && sentence[j] != '\0')
            putchar(sentence[j++]);
        if (i > 0)
            putchar(' ');
    }

    printf("%c\n", terminator);

    return 0;
}

Despite double checking the code, and running through the example input on paper, I've not been able to find an answer.

How come the code produces these different outputs, correct as well as incorrect? What produces the erroneous characters?

Upvotes: 2

Views: 83

Answers (3)

Vlad from Moscow
Vlad from Moscow

Reputation: 310980

For starters the program has undefined behavior because the variable terminator is not initialized. The user can press the Enter key without supplying one of these characters ".!?"

for (i = 0; (ch = getchar()) != '\n' && i < 100; i++) {
                             ^^^^^^^                       

In this case this statement

printf("%c\n", terminator);

will output an indeterminate value.

Moreover the user can interrupt the loop pressing a corresponding key combination but the loop does not process such a situation.

If the user pressed the Enter key in the very beginning of the loop then i will be equal to 0 In this case the inner while loop

while (i >= 0) {
    while (sentence[--i] != ' ' && i != 0)
                    ^^^
        ;

will invoke undefined behavior.

Moreover before the terminating character (".!?") the sentence can contain spaces. Thus this loop

    while (sentence[--i] != ' ' && i != 0)
        ;
    j = i == 0 ? 0 : i + 1;

again will be incorrectly terminated. That is j will be equal to i + 1 where a zero character is stored (provided that the user did not entered all 100 elements of the array sentence).

Apart from this the program does not output existent number of spaces between words. It only tries to output one space

putchar(' ');

Take into account that the user can enter for example the tab character '\t' instead of the space character ' '.

Below there is shown how the program can be written.

#include <stdio.h>
#include <ctype.h>
#include <string.h>

int main(void) 
{
    const char *punctuation = ".?!";

    enum { N = 100 };
    char s[N] = "";
    char terminator = '\0';
    
    printf( "Enter a sentence: " );
    
    size_t n = 0;

    for ( int c; n < N && ( c = getchar() ) != EOF && c != '\n'; n++ )
    {
        if ( strchr( punctuation, c ) )
        {
            terminator = c;
            break;
        }
        
        s[n] = c;
    }
    
    printf( "Reversal of sentence: " );

    putchar( '\"' );
    
    size_t i = 0;
    
    while ( i != n && isblank( ( unsigned char )s[i] ) ) putchar( s[i++] );
    
    for ( size_t j = n; i != n; )
    {
        while ( i != n && !isblank( ( unsigned char )s[i] ) ) i++;
        
        while ( isblank( ( unsigned char )s[j-1] ) ) j--;

        size_t k = j;
        while ( j != 0 && !isblank( ( unsigned char )s[j-1] ) ) j--;
                
        for ( size_t l = j; l != k; l++ ) putchar( s[l] );

        while ( i != n && isblank( ( unsigned char )s[i] ) ) putchar( s[i++] );
    }
    
    if ( terminator ) putchar( terminator );
    putchar( '\"' );
    
    return 0;
}

The program output might look like

Enter a sentence: you can  cage   a    swallow     can't      you?
Reversal of sentence: "you can't  swallow   a    cage     can      you?"

As you can see the program preserved all spaces contained in the entered sentence.

Upvotes: 0

malcolm_mloclam
malcolm_mloclam

Reputation: 11

Yes, as stated in the answer above the problem is within this block

while (i >= 0) {
        while (sentence[--i] != ' ' && i != 0) ;
    ....

You should change the i != 0 part into i >= 0, this should solve the thing

The problem is that i decrementation sentence[--i] happens before i != 0 and so imagine the while loop starting with i = 0 - this will mean that sentence[i - 1] will (likely) not be ' ' and i will not be equal to zero.

Upvotes: 0

dash-o
dash-o

Reputation: 14452

Most likely, the problem is with the exit condition for the while loop used to print the sentence in reverse

    while (i >= 0) {
        while (sentence[--i] != ' ' && i != 0) ;
    ....

Consider the case where the code is going to print the first word (i=3):

  • The second while will decrement i all the way to 0
  • then the code will print the word 'you' (positions 0 to 2, inclusive)
  • At this point i=0, the first while still is true
  • The second while will decrement i to -1, and will continue to decrement it to -2, -3, until a space is found.
  • The code will print the word with indices of -1, -2, -3, and will print a string based on those undefined values.

Upvotes: 2

Related Questions