How can I get an input text to be printed in reverse, with a specified length to each output line

Viewed 66

I need to write a code that takes a user input and outputs a mirror image of the input, with a line break every x characters, where x is a number input by the user.

For example:

Enter the length of the output line: 5
Enter your text (control-d to exit): Hello there
output:
olleH
.ereh
....t

12345

(the dots are spaces)

My current code is:

int main() {
    char input[121], mirror[121];
    int length = 0, i, str = 0, j = 2, reset = 0, k;

    printf("Enter the width of an output line:\n");
        scanf("%d", &length);
    printf("Enter your text (control-d to exit):\n");
       while (scanf("%c", &input[i]) == 1) {
            i++;
       }
       reset = length;
       str = strlen(input);
       printf("\n");
       input[str] = '\0';
    for (i = 0; i < ((str / length) + 1); i++) {
       for (k = 0; k < length; k++) {
            if ((length - k) >= 0) {
                mirror[k] = input[reset - k];
                printf("%c", mirror[i]);
            }

            else if ((length - k) < 0) {
                printf("\n");
                mirror[k] = input[reset + 1];
                reset = (j * reset);
                j++;
            }
       }
        }
    return 0;
}

My output is nowhere near correct, and although I've had previous attempts that were closer to correct, overall I am not sure how to really approach this problem.

2 Answers

Your algorithm went off the rails, but we can get the train back up on the track. The key is to recognize you have to reverse each WORD in the string preserving whitespace and then output characters in groups of width characters at a time from your output array. If the final group has output that would be beyond the length of the string, output spaces and then the final characters.

That and cleaning up your code, validating all input and getting rid of scanf() that is full of pitfalls for the new C programmer, you could do the following:

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

#define MAXC 128    /* if you need a constant, #define one (or more) */

int main (void) {

  char input[MAXC],
       output[MAXC];
  size_t  length = 0,     /* strlen returns size_t not int */
          width = 0,
          i = 0; 

  /* just reuuse the 'input' buffer to read width and use sscanf() for
   * the conversion VALIDATING both by CHECKING THE RETURN.
   */
  fputs ("Enter the width of an output line : ", stdout);
  if (!fgets (input, MAXC, stdin) || sscanf (input, "%zu", &width) != 1) {
    puts ("(user canceled input) or invalid integer input");
    return 1;
  }
  
  /* read/validate input, trim \n and get length */
  fputs ("Enter your text : ", stdout);
  if (!fgets (input, MAXC, stdin)) {
    puts ("(user canceled input)");
    return 1;
  }
  input[strcspn (input, "\n")] = 0;             /* trim \n from end */
  length = strlen (input);                      /* get input length */
  
  putchar ('\n');     /* use putchar() to output a single-character */
  
  /* reverse words in input preserving whitespace */
  for (i = 0; input[i];) {        /* loop each char in input */
    if (isspace (input[i])) {     /* if space, copy to output */
      output[i] = input[i];
      i++;                        /* increment loop index */
    }
    else {  /* otherwise, not space, get length of word, save index */
      size_t wordlen = strcspn (input + i, " \t\n"),
             index = i;
      if (!wordlen) {             /* if wordlen is zero, at end, break */
        break;
      }
      while (wordlen--) {         /* reverse loop wordlen filling output */
        output[i++] = input[index + wordlen];   /* increment loop index */
      }
    }
  }
  output[i] = 0;      /* nul-terminate output */
  
  for (i = 0; i < length;) {      /* loop while i < length */
    size_t j = width;             /* counter for width characters */
    while (j--) {                 /* loop width number of times */
      if (j + i >= length) {      /* if i + j outside string put space */
        putchar (' ');
      }
      else {  /* otherwise */
        putchar (output[i++]);    /* output next char in output */
      }
    }
    putchar ('\n');               /* tidy up with newline */
  }
}

(note: you can trim the '\n' and save the length in a single call with input[(length = strcspn (input, "\n"))] = 0;, but up to you)

Also note, the last if-else can be considerably shortened using a ternary operator. That would reduce the final comparison to:

      putchar (j + i >= length ? ' ' : output[i++]);

Up to you which you want to use.

Example Use/Output

Now your example output is correctly reproduced, e.g.

$ ./bin/revstr
Enter the width of an output line : 5
Enter your text : Hello there

olleH
 ereh
    t

Or if you added a character, e.g.

$ ./bin/revstr
Enter the width of an output line : 5
Enter your text : Hello Mickey

olleH
 yekc
   iM

Look things over and let me know if you have further questions.

Relax... take a deep breath... and think slowly about what's needed...

It is a standard 'beginner' notion that things are complicated and involve lots of variables and esoteric calculations. It takes a bit of experience to learn to pause-and-assess the problem BEFORE touching the keyboard.

Consider this:

int main() {
    char input[ 120 + 1]; // some variables
    int olen = 0;

    // some user input
    printf( "Width of an output line: " );
    scanf( "%d", &olen );
    /* omitting validation for brevity */

    // more user input using "scanf()" parameters that work
    printf( "Enter text: ");
    if( scanf( " %120[^\n]", input ) != 1 ) {
        fprintf( stderr, "scanf failed\n" );
        return 1;
    }

    // Now, output from the "back end", while counting 'modulo' to insert line breaks.
    int up = 1;
    for( int i = strlen( input ) - 1; i >= 0; i-- ) {
        putchar( input[ i ] );
        if( up++ % olen == 0 ) // time for a 'line break' ?
            putchar( '\n' );
    }
    // All done.

    return 0;
}
Width of an output line: 5
Enter text: Hello there
ereht
 olle
H
Width of an output line: 8
Enter text: Twas brillig and the slithy toves...
...sevot
.yhtils. // some '.' added in post processing for clarity.
eht dna.
gillirb.
sawT...

There's no need for a 2nd buffer, or for a lot of variables whose values you begin to lose track of... Just keep things simple!

An exercise is to modify the code above to reverse the string "in place", then output substrings of the right length on separate lines. Also, reverse each substring independently.

Related