views:

70

answers:

4

I'm brand new to C and am trying to learn how to take a string and print it using a function. I see examples everywhere using while(ch = getchar(), ch >= 0), but as soon as I put it into a function (instead of main()), it ceases to work. Right now, it's stuck in an endless loop... why is that?

// from main():
// printString("hello");

void printString(char *ch)
{
    while (*ch = getchar(), *ch >= 0)
    putchar(*ch);
}
A: 

I would just do printf("%s",str); or puts(str);

Kyle
Or `puts`. Don't use an elephant gun to kill a flea.
Ben Voigt
It has to be done in a function because the function is going to actually format the string... sorry if I didn't explain that properly.
Brett Alton
@Ben Voigt: It is not he same. `puts` adds the `\n` at the end unconditionally. You might want it, or you might not want it.
AndreyT
@Andrey: I guess I don't use it enough... anyway `fputs` neither adds a trailing newline nor wastes time parsing any format string, so that would be best.
Ben Voigt
+2  A: 

Based on your description, you just want:

void printString(char *ch)
{
  while(*ch) {
     putchar(*ch);
     ch++;
  }
}

Your original function:

void printString(char *ch)
{
    while (*ch = getchar(), *ch >= 0)
    putchar(*ch);
}

Does a lot of stuff:

  1. reads characters from stdin
  2. stores the character read from stdin into the first char pointed to by ch (this might not even work if you pass in a string literal.
  3. writes characters to stdout.
  4. Terminates when the read character is < 0 (this won't work on some platforms. Since the result is stored in a char you can't distinguish between EOF and a valid character. ch should be an int, as getchar() returns an int so you can check for EOF)
nos
You can also use puts.
Paul Hankin
Probably without the missing brace, though.
Porculus
Terminates NOT when the read character is < 0; Terminates ALSO when the read character is == 0
@user411313 no, the loop terminates when the read character is less than 0 ( < 0)
nos
+2  A: 

getchar() reads user input from stdin. If you want to print the string being passed in then there's no need for getchar().

Let's take it step by step. The loop you have reads one character a time from stdin until it reaches end-of-file. That's what the ch >= 0 test checks for: keep reading as long as we're getting valid characters. For printing the characters of a string, the condition changes. Now a valid character is anything that's not NUL ('\0'). So we'll change the loop condition to:

while (*ch != '\0')

Next is figuring out the loop body. putchar(*ch) is fine; we'll leave that there. But without getchar() we have to figure out what the equivalent statement to "get the next character" is.

That would be ch++. This advances the ch pointer to the next character in the string. If we put that at the end of the loop then we'll print a character, advance one space, and then check if the next character is non-NUL. If it is then we print it, advance, and check.

while (*ch != '\0') {
    putchar(*ch);
    ch++;
}
John Kugelman
While this is correct, it's not idiomatic. Most people would simplify `*ch != '\0'` to `*ch`, which means exactly the same; and it's also possible to write the body in a single command, `putchar(*ch++);` -- understanding why that is possible is essential if one is to grasp the behaviour of `++` in C.
Porculus
+1  A: 

What happens here is the following:

  1. in the function main you call printString with a pointer to the string "hello"
  2. the printString function attempts to read a character with getchar()
  3. and save that character in the place of the 'h'

The rules of the language say that attempting to change that 'h' is Undefined Behaviour. If you're lucky, your program crashes; if you're very unlucky it will appear the program works.

In short: getchar() is used for reading; putchar() is used for writing.

And you want to write 5 letter: 'h', 'e', 'l', 'o', and another 'o'.

    hello
    ^            ch is a pointer
    ch           *ch is 'h' -- ch points to an 'h'

Is there something after that last 'o'? There is! A '\0'. The zero byte terminates the string. So try this (with printString("hello");) ...

void printString(char *ch)
{
    putchar(*ch); /* print 'h' */
    ch = ch + 1;  /* point to the next letter. */
                  /* Note we're changing the pointer, */
                  /* not what it points to: ch now points to the 'e' */
    putchar(*ch); /* print 'e' */
    ch = ch + 1;  /* point to the next letter. */
    putchar(*ch); /* print 'l' */
    ch = ch + 1;  /* point to the next letter. */
    putchar(*ch); /* print 'l' */
    ch = ch + 1;  /* point to the next letter. */
    putchar(*ch); /* print 'o' */
    ch = ch + 1;  /* point to the next letter. What next letter? The '\0'! */
}

Or you can write that in a loop (and call from main with different arguments) ...

void printString(char *ch)
{
    while (*ch != '\0')
    {
        putchar(*ch); /* print letter */
        ch = ch + 1;  /* point to the next letter. */
    }
}
pmg