Copying the input from `getchar()` to another variable

Viewed 734

In the following code example from K&R's book, if I replace putchar(c) with printf("%c", c) the code works the same. But if I replace it with printf("%d", c) it gives gibberish output.

#include <stdio.h>
int main() {
  int c;
  c = getchar();
  while (c != EOF) {
    putchar(c);
    c = getchar();
  }
}

From here, I learned that the getchar() converts the stdin to an 8-bit character whose value ranges from 0 to 255.

Now I want to print the value of c using putchar(c) in one line and printf("%d", c) in another line. So I wrote the following code:

#include <stdio.h>

int main() {
  int c, b;

  c = getchar();
  b = c;
  while (c != EOF && c != 10) {
    printf("%c",c);
    c = getchar();
  }
  printf("\n");
  while (b != EOF && b != 10) {
    printf("%d\t",b);
    b = getchar();
  }
}

I used the condition c != 10 as the newline character is read as 10 by getchar(). I expected the code to work as

$ ./a.out
783
783
55 56 51

but the program terminates as

$ ./a.out
783
783
55

I understand that getchar() takes input from stdin and the variable b is not stdin. So how should I copy the variable c to b so that my program works as I expect it to?

3 Answers

The problem is that your code does not (and cannot, as it stands) 'remember' the inputs you gave in the first loop. So, after you have finished that loop, your second loop is wanting to read in the characters for b (after it has output the first value, which is remembered from the earlier b = c line).

So, after outputting 55 (the integer value of the character 7), it is waiting for further input.

Probably the easiest way to get the output that you're looking for is to have an array of input characters. Then, you can output the %c values as you read them (as before), then re-run the outputs using the %d format in a subsequent for loop.

Here is a demonstration that does what I think you're after:

#include <stdio.h>
#define MAXINS 20 // Set to the maximum number of input characters you want to allow
int main()
{
    int c[MAXINS];
    int i = 0, n = 0;
    c[0] = getchar();
    while (i < MAXINS && c[i] != EOF && c[i] != 10) {
        printf("%c", c[i]);
        c[++i] = getchar();
        ++n;
    }
    printf("\n");
    for (i = 0; i < n; ++i) {
        printf("%d\t", (int)(c[i]));
    }
    return 0;
}

Feel free to ask for further clarification and/or explanation.

EDIT: On the point in the your first paragraph, "But if I replace it with printf("%d", c) it gives gibberish output." Well, when I try the following code and give 783 and then hit return (which generates a newline) I get the expected 55565110 as the output:

int main()
{
    int c;
    c = getchar();
    while (c != EOF) {
        printf("%d", c);
        c = getchar();
    }
    return 0;
}

This may look like gibberish, but it's just the same output as you 'expect' in your later code, but without the spaces and with the addition of the 10 for the newline.

You need to have every character stored, because once you read a char from stdin, it is not present in stdin anymore.

Since you want the newline character in the end as a part of the input, you should use fgets to take the input.

Say you are taking an input that could have a maximum of 100 characters.

#include <stdio.h>

int main(void) {
    char c[100]; // A char array
    fgets(c,100,stdin);
    int x=0;
    while (c[x] != 10 && c[x] != EOF)
        printf("%c",c[x++]);
    printf("\n");
    x = 0;
    while (c[x] != 10 && c[x] != EOF) // You can simply compare it with the newline character too.
        printf("%d ",c[x++]);
    printf("\n");
    return 0;
}

There are many ways to do this. You can also read stdin character-by-character ans store it in an array. However, since you need to display the ASCII values of the characters in another line after displaying the characters themselves, you will have to store them in an array.

You are copying only the first input, to copy the whole string you need to store each input in a buffer and check if the string doesn't overflow that buffer on each iteration:

int main(void)
{
    enum {size = 256};
    char buffer[size];
    size_t count = 0;
    int c;

    while ((c = getchar()) && (c != '\n') && (c != EOF))
    {
        printf("%c", c);
        if (count < size)
        {
            buffer[count++] = (char)c;
        }
    }
    printf("\n");
    for (size_t iter = 0; iter < count; iter++)
    {
        printf("%d\t", buffer[iter]);
    }
    printf("\n");
}

If you don't want to limit the buffer to an arbitrary size then you need to change your approach to use dynamic memory (realloc or a linked list)

Related