K&R C Exercise 1-19: Reverse a String in C

Exercise 1-19. Write a function reverse(s) that reverses the character string s. Use it to write a program that reverses its input a line at a time.

Approach

The core algorithm is the classic two-pointer swap: place one index at the start of the string (i = 0) and one at the end (j = last character), swap those two characters, move both pointers toward the middle, and repeat until they meet or cross. It is an in-place reversal — no second array is needed, only a single temporary variable.

The one trap K&R plants here is the \n stored at the end of each line. Because getline2 saves the newline before the null terminator, a naive reversal of "hello\n" would produce "\nolleh" — the newline moves to the front and every line begins with a blank line. The fix is to detect the trailing \n and step j back one position past it before starting the swap loop, leaving the newline anchored where printf expects it.

Solution

/* K&R Exercise 1-19: reverse each input line
   Compile: gcc -ansi -Wall exercise1-19.c -o exercise1-19 */

#include <stdio.h>

#define MAXLINE 1000

int getline2(char line[], int maxline);
void reverse(char s[]);

int main(void)
{
    char line[MAXLINE];
    while (getline2(line, MAXLINE) > 0) {
        reverse(line);
        printf("%s", line);
    }
    return 0;
}

/* getline2: read a line into line[], return length */
int getline2(char line[], int maxline)
{
    int c, i;
    for (i = 0; i < maxline - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
        line[i] = c;
    if (c == '\n')
        line[i++] = '\n';
    line[i] = '\0';
    return i;
}

/* reverse: reverse the string s[] in place */
void reverse(char s[])
{
    int i, j;
    char temp;

    /* walk j to the last character before '\0' */
    for (j = 0; s[j] != '\0'; ++j)
        ;
    --j;

    /* skip trailing newline so it stays at the end */
    if (s[j] == '\n')
        --j;

    /* swap from both ends toward the middle */
    for (i = 0; i < j; ++i, --j) {
        temp = s[i];
        s[i] = s[j];
        s[j] = temp;
    }
}

Compile and Run

gcc -ansi -Wall exercise1-19.c -o exercise1-19
./exercise1-19

Type a line and press Enter. The program immediately prints it reversed. Press Ctrl+D (Unix/macOS) or Ctrl+Z then Enter (Windows) to end input. You can also pipe input directly:

echo "Hello, World!" | ./exercise1-19
printf "racecar\nabc\n" | ./exercise1-19

Sample Output

$ printf "Hello, World!\nracecar\na\n" | ./exercise1-19
!dlroW ,olleH
racecar
a

"racecar" is a palindrome — it reads the same forwards and backwards, so it appears unchanged. A single-character line like "a" is trivially its own reverse.

How the Two-Pointer Swap Works

Tracing reverse on "Hello\n", stored as H e l l o \n \0 at indices 0–6:

  1. The for loop advances j until s[j] == '\0', leaving j = 6. Then --j gives j = 5, pointing at \n.
  2. s[5] == '\n', so j becomes 4, pointing at o. The newline is now outside the swap range.
  3. Iteration 1 — i = 0, j = 4: swap Hoo e l l H \n \0
  4. Iteration 2 — i = 1, j = 3: swap elo l l e H \n \0
  5. Iteration 3 — i = 2, j = 2: i < j is false, stop. The middle l needs no swap.
  6. Result: "olleH\n" — correct output with newline still at the end.

The i < j condition handles both even- and odd-length strings correctly. When the indices cross (even length) or meet (odd length), every character has already been placed in its final position.

What This Exercise Teaches

  • Two-pointer technique: working inward from both ends of an array is a pattern that reappears constantly — in binary search, palindrome checking, partitioning, and more. This exercise is its simplest form.
  • The temp-variable swap: temp = s[i]; s[i] = s[j]; s[j] = temp; is the fundamental way to exchange two values in C. Without temp, the first assignment would overwrite the value you still need.
  • In-place algorithms: this reversal uses O(1) extra space — just one char temp — regardless of string length. No second array is allocated.
  • Newline anchoring: any function that operates on lines stored by getline must handle the embedded \n deliberately. Forgetting it produces subtly wrong output that looks almost right until you look carefully.
  • Separating concerns: getline2 handles I/O; reverse does one job. This clean split between reading data and processing it is the K&R approach to program structure, even at the simplest level.

Set Up Your C Environment

To compile and run this solution you need GCC installed. If you haven’t set up C development on your machine yet:

← Exercise 1-18  | 
Chapter 1 Solutions  | 
Exercise 1-20 →

Book:
The C Programming Language, 2nd Ed — Kernighan & Ritchie

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>