Very simple C question using getchar() and putchar() - c

Hello I am teaching myself C and going through the K & R book and I am having some trouble (I am running OS X). This is from section 1.5.1 "File Copying" which is supposed to take a character as input, then output the character. Here is the code:
#include <stdio.h>
/* -- Copy input to output -- */
int main(void)
{
int c;
c = getchar();
while ( c != EOF ) {
putchar(c);
c = getchar;
}
}
So, I think my problem is not with the code itself but with compling and running. First of all, when compiling I get the following errors
/Volumes/Goliath/Dropbox/C programs/prog1_5_1.c: In function ‘main’:
/Volumes/Goliath/Dropbox/C programs/prog1_5_1.c:12: warning: assignment makes integer from pointer without a cast
/Volumes/Goliath/Dropbox/C programs/prog1_5_1.c:16: warning: control reaches end of non-void function
Then when I run the output file (in terminal) it has a small space, then when I input a letter, say I type
a
then I hit Return
and I get a new line. If I then hit a new key, the screen starts going crazy with question marks all over the place.
I am not sure if I am making much sense but I am finding this an odd problem to have. Thank you very much in advance

The second assignment should be c = getchar();. By leaving out the parentheses, you're assigning the address of the getchar function to c, which is very much not what you want.
Also, at the end of main you need the line return 0; or similar in order to get rid of the "control reaches end of non-void function" warning.

you missed the () on getchar on line 12. without parenthesis, "getchar" evaluates to the address of the function, which is why you get the pointer-cast-to-int warning

You're missing parenthesis after the 2nd getchar.
This means you're assigning the location in memory of the method to the variable c, which causes an infinite loop as it's never equal to EOF.

Related

Basic getchar()-related function in K&R C book not working? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 years ago.
Improve this question
#include <stdio.h>
main()
{
double nc;
for(nc=0; getchar()!=EOF; ++nc);
printf("%1d\n",nc);
}
This is my first time learning C, and there are a few things I don't seem to understand too well. The for loop has a rather simple structure the only constraint being if getchar does not equal EOF (whatever that value EOF is set to be). Every time getchar does NOT equal EOF, nc gets incremented. Finally we get out of the for loop with nc being adjusted to the length of the string.
However the program is only taking inputs and not displaying the value that should be associated with the length of the character.
What am I not understanding? I'm assuming the book has a much higher chance in being right than me so I guess I'm going wrong somewhere.
The program keeps reading input until it comes to the end of the input. If you're typing on a terminal, you need to find out how to signal the end of the input. On Windows, press Ctrl+Z then Enter. On Unix-like systems (Linux, macOS, etc.), press Ctrl+D at the beginning of a line. Alternatively, make the program read from a file: on a Windows command line, run myprogram.exe <somefile.txt. On a Unix-like command line, run ./myprogram <somefile.txt.
Once the program does reach the end of the file, it'll likely crash or print a nonsensical value, because there's an error in your printf statement. nc is a floating-point value, but %d requires an integer value (more precisely, a value of type int). Here are three combinations that work:
Integer:
int nc;
…
printf("%d\n", nc);
Larger-size integer, like in the first example in K&R — note that it's a lowercase l, not a digit 1:
long nc;
…
printf("%ld\n", nc);
Floating-point number, which may allow larger values (on a modern PC, it allows larger values than long in a 32-bit program, but long allows larger values in a 64-bit program):
double nc;
…
printf("%f\n", nc);
A good compiler would warn you about the mismatch with printf. Make sure that you've enabled warnings. For example, here's what gcc -Wall -O aliman.c has to say about your program:
aliman.c:3:1: warning: return type defaults to ‘int’ [-Wreturn-type]
main()
^
aliman.c: In function ‘main’:
aliman.c:9:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’ [-Wformat=]
printf("%1d\n",nc);
^
aliman.c:13:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
The warning about the return type of main is because main() is an obsolete shortcut, in modern C you need to write int main(). (Make that int main(void) if you're pedantic.) The last warning says that there's no return statement — the main function must return a value (conventionally, it indicates whether the program succeeded or failed). Both topics will be covered in §1.7.
However the program is only taking inputs and not displaying the value
that should be associated with the length of the character. What am I
not understanding? I'm assuming the book has a much higher chance in
being right than me so I guess I'm going wrong somewhere.
The for loop ends only when the standard input signals EOF. This can be done with Ctrl+d on Linux in general. For other operating systems you'd need to find the pendant.
After the for loop ends, the number of characters read will be displayed on standard output.
Some remarks: nc should be an integer. The format string for the printf function suffices to be %d then.
Formatting the source code can help you understand easier. Note that the for loop does not contain the printf (as you might have been assuming).
#include <stdio.h>
main()
{
int nc;
for(nc=0; getchar()!=EOF; ++nc)
;
printf("%d\n",nc);
}
You have three possible options
Change double to int
Change "%d" in the printf() to "%lf"
Cast nc to int like this (int)nc;
It will count '\n' as well
or if you do not to count '\n'
for (int i = 0; i != EOF; !i ? nc = 0 : nc, i != '\n' && i ? nc++ : nc, i = getchar());

Hidden printable text

I build a small program that simply copy the text from an input.txt file to an output.txt file. It works with no apparent problem with the command:
./myCopier.txt < rand.txt > randout.txt
on a GCC89 compiler, used for didactic purposes.
#include<stdio.h>
int main(void){
int c;
while ((c = getchar()) != EOF)
putchar(c);
/*The text in printf() does not appear anywhere*/
printf("My theories and toughts!\n");
}
Later, I add printf() in order to print my thoughts about how the program worked. It compiles without errors or warnings even with restrictive parameters (-Wall), but this text does not appear in any place. By any place, I mean both output.txt and the standard output.
I am thinking that:
The command ./myCopier.exe alone clearly create an endless loop. Without text input there is no EOL character, hence the print() command is never reached.
So, why when the input is provided, the printf() command has no apparent effect? I'd expect the text from printf()to appear on the standard output, just when the loop closes and output.txt is created. Why does it not occur?
My theory is that ./myCopier.txt < rand.txt > randout.txt does not allow it. For some reason, it makes the program only transfer the input to the output, "ignoring" everything does not come from the input. Am I correct? If so, why?
If you are interested in the problem with deeper detail, here is the assembly code:
http://text-share.com/view/79f31f38
Omitting the return statement in main() causes undefined behavior in C89/C90.
Normally, returning from main() forces the output buffer to be flushed. If you omit the return statement, anything can happen.
Try to add return 0 at the end of main() as was required in C90. GCC in c90/gnu90 mode will warn you otherwise: "control reaches end of non-void function".
Try to add fflush(stdout);.

"File Copying" section in K&R

I'm new to programming and I can't seem to get my head around why the following happens in my code, which is:
#include <stdio.h>
/*copy input to output; 1st version */
main()
{
int c;
c = getchar();
while (c != EOF) {
putchar(c);
c = getchar();
}
}
So after doing some reading, I've gathered the following:
Nothing executes until I hit Enter as getchar() is a holding function.
Before I hit Enter, all my keystrokes are stored in a buffer
When getchar() is called upon, it simply goes looks at the first value in the buffer, becomes that value, and then removes that value from the buffer.
My question is that when I remove the first c = getchar() the resulting piece of code has exactly the same functionality as the original code, albeit before I type anything a smiley face symbol immediately appears on the screen. Why does this happen? Is it because putchar(c) doesn't hold up the code, and tries to display c, which isn't yet defined, hence it outputs some random symbol? I'm using Code::Blocks if that helps.
The function you listed will simply echo back to you every character you type at it. It is true that the I/O is "buffered". It is the keyboard input driver of the operating system that is doing this buffering. While it's buffering keys you press, it echoes each key back at you. When you press a newline the driver passes the buffered characters along to your program and getchar then sees them.
As written, the function should work fine:
c = getchar(); // get (buffer) the first char
while (c != EOF) { // while the user has not typed ^D (EOF)
putchar(c); // put the character retrieved
c = getchar(); // get the next character
}
Because of the keyboard driver buffering, it will only echo back every time you press a newline or you exit with ^D (EOF).
The smiley face is coming from what #YuHao described: you might be missing the first getchar in what you ran, so putchar is echoing junk. Probably a 0, which looks like a smiley on your screen.
If you ommit the first getchar(), the code will look like this:
int c;
while (c != EOF) {
putchar(c);
c = getchar();
}
Here, c is uninitialized, so calling putchar(c) the first time will output a garbage value, that's where you get the smiley face.
"I'm new to programming"
You're not advised to learn programming using C (and the difficulties you're going through are because of the C language). For example, my first computer science classes were in pascal. Other univesities may use scheme or lisp, or even structured natural languages to teach programming. MIT's online classes are given in python.
C is not a language you would want to use in the first months of programming. The specific reason in your case is due to the fact that the language allowed you to use the value of an uninitialized value.
When you declare the integer variable "c", it gets an implicitly reserved space on the program stack, but without have any meaningful value: it's "trash", the value is whatever value was already on memory at that time. The C language requires that the programmer implicitly knows that he needs to assign some value before using a variable. Removing the first getchar results in uses before assignment in the while condition (c != EOF) and putchar(c), both before c has any meaningful value.
Consider the same code rewritten in python:
import sys
c = sys.stdin.read(1)
while c != '':
c = sys.stdin.read(1)
sys.stdout.write(c)
Remove the initial read and you get the following error:
hdante#aielwaste:/tmp$ python3 1.py
Traceback (most recent call last):
File "1.py", line 3, in <module>
while c != '':
NameError: name 'c' is not defined
That's a NameError: you used the value without assigned to it resulted in a language error.
For more information, try an online course, for example:
http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-00-introduction-to-computer-science-and-programming-fall-2008/video-lectures/
About uninitialized values:
http://en.wikipedia.org/wiki/Uninitialized_variable

Learning C (via K&R) using xcode

I'm learning C with The C Programming Language (K&R).
Since I don't particularly want to bob back and forth between a text editor and running gcc, I've decided to use xcode as an IDE. So far, I've been able to follow the book's examples without a problem up until section 1.5.2.
When given the valid (?) program...
#include <stdio.h>
void main()
{
long nc;
nc = 0;
while (getchar() != EOF)
++nc;
printf("%ld\n", nc);
}
...I receive no final output telling me how many characters were in my input. I am entering my input via the xcode console window.
Upon some debugging, it looks like my program gets stuck in the while loop, and never encounters the EOF token. To accommodate for this, I've instead substituted a newline as the new condition, by replacing EOF with "\n", which also does nothing and gives me a int to pointer comparison warning.
What am I doing wrong here?
Will I be able to follow K&R using xcode?
Type ^D (control-d) to send an EOF.
If you want to break on a newline, you need to compare the return value of getchar to '\n', not "\n". The former is the actual char value of a newline; the latter is a pointer to a char with that value. If that doesn't make sense to you yet, don't worry, it will once you've read more.

why does this happen (see image)?

Why does the following have the effect it does - it prints a terminal full of random characters and then exits leaving a command prompt that produces garbage when you type in it. (I tried it because I thought it would produce a seg fault).
#include <stdio.h>
int main(){
char* s = "lololololololol";
while(1){
printf("%c", *s);
s++;
}
}
it was compiled with:
gcc -std=c99 hello.c
It will eventually seg fault, but before that it'll print out whatever bytes are in the same page. That's why you see random chars on the screen.
Those may well include escape sequences to change (say) the character encoding of the console. That's why you end up with gibberish when you type on the console after it's exited, too.
Because you have an infinite loop (while(1)), and you keep getting the current value of pointer (*s), and then moving the pointer one char forward (s++). This has the effect of marching well past the end of the string into "garbage" (uninitialized memory), which gets printed to the console as a result.
In addition to what everyone else said in regards to you ignoring the string terminal character and just printing willy-nilly what's in memory past the string, the reason why your command prompt is also "garbage" is that by printing a particular "unprintable" character, your terminal session was left in a strange character mode. (I don't know which character it is or what mode change it does, but maybe someone else can pipe in about it that knows better than I.)
You are just printing out what is in memory because your loop doesn't stop at the end of the string. Each random byte is interpreted as a character. It will seg fault when you reach the end of the memory page (and get into unreadable territory).
Expanding ever so slightly on the answers given here (which are all excellent) ... I ran into this more than once myself when I was just beginning with C, and it's an easy mistake to make.
A quick tweak to your while loop will fix it. Everyone else has given you the why, I'll hook you up with the how:
#include <stdio.h>
int main() {
char *s = "lolololololololol";
while (*s != '\0') {
printf("%c", *s);
s++;
}
}
Note that instead of an infinite loop (while(1)), we're doing a loop check to ensure that the pointer we're pulling isn't the null-terminator for the string, thus avoiding the overrun you're encountering.
If you're stuck absolutely needing while(1) (for example, if this is homework and the instructor wants you to use it), use the break keyword to exit the loop. The following code smells, at least to me, but it works:
#include <stdio.h>
int main() {
char *s = "lolololololololol";
while (1) {
if (*s == '\0')
break;
printf("%c", *s);
s++;
}
}
Both produce the same console output, with no line break at the end:
lolololololololol
Your loop doesn't terminate, so println prints whatever is in the memory after the text you write; eventually it will access memory it is not allowed to read, causing it to segfault.
You can change the loop as the others suggested, or you can take advantage of fact that in c, zero is false and null (which terminates all strings) is also zero, so you can construct the loop as:
while (*s) {
Rather than:
while (*s != '\0')
The first one may be more difficult to understand, but it does have the advantage of brevity so it is often used to save a bit of typing.
Also, you can usually get back to your command prompt by using the 'reset' command, typing blindly of course. (type Enter, reset, Enter)

Resources