What is normal C getchar/putchar behaviour? - c

I am working through the exercises in Stephen Prata's "C Primer Plus", and have a question re. listing 8.1:
/* echo.c -- echoes input */
#include <stdio.h>
int main(void)
{
char ch;
while ((ch = getchar()) != '#')
putchar(ch);
// while ((ch = getchar()) != '.')
// putchar(ch);
return 0;
}
The original code did not include the comments; I added them and they are the subject of my question. If I uncomment those lines there is no discernible effect on the output. It still ends at the # sign, without printing it. No additional text is displayed and I am returned to the command prompt.
Why is that? Also, does the # get consumed by getchar()? That was why I included the second loop - I was trying to display any remaining characters in the buffer, out of curiosity. Obviously, I don't know what I'm doing!

Related

How to best parse comments lines in a file with C

Okay so I'm trying to read in a PPM file (p3 format) and I want to read the comments (which are #s in ppm files).
The problem is that I don't know how to make C do what is in my head, heres what I want it to do.
read the file
where # appears, store all characters until the %\n character appears
repeat until all comments are read
I understand that I should be using some variations of getc, fgets and fscanf but I don't know how to apply them in this context.
I would put some code up showing what i've tried with getc, fgets and fscanf but to be brutally honest I have no idea how to use any of those functions and none of the info I can find seems to help and I really don't think any of my implementations are even doing anything.
Does anyone /is anyone willing to show me an example of how to parse a line with any of these functions?
Simple, two-state FSM, reading one character at a time:
#include <stdio.h>
int main(void)
{
int ch, state;
for(state=0;; ) {
ch = getc(stdin);
if (ch == EOF) break;
if (state) {
putc(ch, stdout);
if (ch == '\n') state=0;
continue;
}
if (ch == '#') state = 1;
}
return 0;
}
Using ./a.out <fsm.c
include <stdio.h>
') state = 1;

K&R Chapter 1.5.4: "How would you test the word count program?"

Beginner here.
In the ANSI C textbook by K&R, page 20, they ask: How would you test the word count program?
I have copied exactly from the text book, using the CodeBlocks IDE, console application. I have seen many great input tests online, but my question is even dumber. How do I actually input something? Nothing happens when I press enter. Do I have this problem because I am using an IDE and therefore not learning how to run C programs properly?
Thanks in advance. I added a picture to show you what I mean
Here is the code:
#include <stdio.h>
#define IN 1 /* inside a word */
#define OUT 0 /* outside a word */
/* counts lines, words and characters as input */
main()
{
int c, nl, nw, nc, state;
state = OUT;
/* set these three constants to 0: */
nl = nw = nc = 0;
while ((c = getchar()) != EOF){
++nc;
if (c == '\n')
++nl;
/* || == OR (&& == AND)
evaluation of the following line
will stop as soon as the truth or
falsehood is known, so the order matters */
if (c == ' ' || c == '\n' == c == '\t')
state = OUT;
else if (state == OUT){
state = IN;
++nw;
}
}
printf("%d %d %d\n", nl, nw, nc);
}
On MacOS:
gcc kr_wc.c -o kr_wc
./kr_wc < example_text.txt
Example output:
40 260 1397
Where example_text.txt is this file:
1.5.4 Word Counting
The fourth in our series of useful programs counts lines, words, and
characters, with the loose definition that a word is any sequence of
characters that does not contain a blank, tab or newline. This is a
bare-bones version of the UNIX program wc.
#include <stdio.h>
#define IN 1 /* inside a word */
#define OUT 0 /* outside a word */
/* count lines, words, and characters in input */
int main() {
int c, nl, nw, nc, state;
state = OUT;
nl = nw = nc = 0;
while ((c = getchar()) != EOF) {
++nc;
if (c == '\n')
++nl;
if (c == ' ' || c == '\n' || c == '\t')
state = OUT;
else if (state == OUT) {
state = IN;
++nw;
}
}
printf("%d %d %d\n", nl, nw, nc);
}
Every time the program encounters the first character of a word, it
counts one more word. The variable state records whether the program
is currently in a word or not; initially it is "not in a word", which
is assigned the value OUT. We prefer the symbolic constants IN and
OUT to the literal values 1 and 0 because they make the program more
readable. In a program as tiny as this, it makes little difference,
but in larger programs, the increase in clarity is well worth the
modest extra effort to write it this way from the beginning. You'll
also find that it's easier to make extensive changes in programs
where magic numbers appear only as symbolic constants.
The program to count words in K&R 2nd edition is made to run on an environment in which you signal the end of input somehow. Normally, as they used UNIX all the time, they used Ctrl-D sequence (which is valid if you run the program in Linux or any Unix-like operating system) This has been so since the early beginning of the UNIX system.
Windows signals the end of input in a console application by the input of a Ctrl-Z (probably followed by a keyboard return key)
If you redirect the input from a file (as when you say a.out <my_input_file.txt) you'll get the number of words at the end, when there's no more input in the file.
You are running the program in an IDE, which is something that normally hides you where standard input and standard output go, or how to signal the window you show how to say that there's not more input to the program.
For the program to get to it's end, you have first to know how to get to an end on input.
The examples in K&R omit a return type of main, which is not valid in modern C, so add int before main():
#include <stdio.h>
#define IN 1 /* inside a word */
#define OUT 0 /* outside a word */
/* counts lines, words and characters as input */
int main()
{
int c, nl, nw, nc, state;
state = OUT;
/* set these three constants to 0: */
nl = nw = nc = 0;
while ((c = getchar()) != EOF){
++nc;
if (c == '\n')
++nl;
/* || == OR (&& == AND)
evaluation of the following line
will stop as soon as the truth or
falsehood is known, so the order matters */
if (c == ' ' || c == '\n' == c == '\t')
state = OUT;
else if (state == OUT){
state = IN;
++nw;
}
}
printf("%d %d %d\n", nl, nw, nc);
}
"How do I actually input something? Nothing happens when I press enter."
If you got problems with your IDE just run it online.
"How would you test the word count program"?
To cite the authors of a bundle of K&R solutions with an answer to that particular question here:
It sounds like they are really trying to get the programmers to learn how to do a unit test. I would submit the following:
input file contains zero words
input file contains 1 enormous word without any newlines
input file contains all white space without newlines
input file contains 66000 newlines
input file contains word/{huge sequence of whitespace of different >kinds}/word
input file contains 66000 single letter words, 66 to the line
input file contains 66000 words without any newlines
input file is /usr/dict contents (or equivalent)
input file is full collection of moby words
input file is binary (e.g. its own executable)
input file is /dev/null (or equivalent)
66000 is chosen to check for integral overflow on small integer machines.

Reading delete keystroke in c

I have encountered something I don't have a clear grasp on. I am having trouble reading the delete input from my MacBook Air. I am writing a program in c to read the input, and have used the following escape sequence character:
c = '127'
I can set the variable c to the decimal value of 8, which from my understanding is the backspace escape sequence. And also in Terminal>Preferences>Advanced, I check the box that enables delete to send Control-H.
Once I do the mentioned things above, I can read the input setting c variable as the following:
c = '8'
Here is my code to attempt to read the delete key from my MacBook
Air:
#include <stdio.h>
main() {
/* Copy program input to program output,
replacing each tab by \t,
each backspace by \b,
and each backslas by \\.
This makes tabs and backspaces visible in an unambiguous way.
*/
int c; // a variable for a character
while((c = getchar()) != EOF) {
if (c == '\t')
printf("\\t");
// check box found in:
// Terminal>Preferences>Advanced>Delete sends Control-H
// default setting DOES NOT send Control-H
// The Delete key does not appear to work with the ascii decimal character value 127.
if (c == '\127')
printf("Print to the screen if Delete key is detected.");
if (c == '\\')
printf("\\\\");
if (c != '\t')
if (c != '\b')
if (c != '\\')
putchar(c);
}
}
Try the following code and see what happens:
#include <stdio.h>
#include <stdlib.h>
int
main() {
int c;
system("stty raw -echo");
while (1) {
c = getchar();
if (c == 3) break; // exits when Ctrl-C is pressed
printf("pressed code: %d\r\n", c);
}
system("stty -raw echo");
return 0;
}
Hope this helps.
The reason that you can't read it is that it is not actually there. Using the delete code to delete characters is inefficient, so most programs actually delete the character instead of adding a delete character in order to hide the previous character.

count tabs in C (fails)

So, I'm supposed to be creating a program in C to count: "blanks, tabs, and spaces". My code is provided below (including comments). you'll see that I have commented the areas of the code that is tasked with counting, and displaying the count of, tabs.
As it stands, the program counts "Blanks" and "Lines" accurately, but "Tabs" always results in "0". I've combed over the tiny code again and again looking for typoes or something, but have found no reason why '\t' fails to be counted. Then I came here and read through a few posts dealing with this same challenge. Thus far, I have found nothing anywhere which would shed any light on the problem I am experiencing with my code.
please, look it over, compile it, and test it out yourself to verify.
If anyone can tell me where my mistake is, that is causing my code not to count "Tabs" (as desired), that would be fantastic.
thank you.
#include <stdio.h>
/* count blanks (" "), tabs (\t), and newlines (\n) */
main()
{
int c, nb, nt, nl;
nb = nt = nl = 0;
while ((c = getchar()) != EOF)
if (c == ' ')
++nb;
else if (c == '\t')
++nt; /* fails to accumulate count */
else if (c == '\n')
++nl;
printf("Spaces:\t%d\n", nb);
printf("Tabs:\t%d\n", nt); /* fails to report new tabs (\t) */
printf("Lines:\t%d\n", nl);
}

My c program to remove lines from a text file works on a small file, but has a stacksmash error with a large file

I am working on a program to filter a list of craigslist results; I want to find a relatively cheap room for rent. The finished program will remove lines that have a price over $600, and create a new file, but for now I am removing every line with a $ character, and printing to the terminal.
The program works fine when run on its own source, but when I run it on an html page of craigslist results saved from Firefox, it prints until the closing html bracket and throws a stack smashing detected warning and a backtrace. I am learning C from K&R so if this code looks antiquated that's why.
# include <stdio.h>
# define MAXLINE 300
main()
{
char line[MAXLINE];
int c;//current character
int p = 0;//position in the line
int flag = 0;//there is a dollar sign
while ((c = getchar()) != EOF){
line[p++] = c;
if (c == '$'){
flag = 1;
}
if (c == '\n'){
if(flag == 0){//there was no $, print the line
int i;
for(i=0;i<p;i++){
putchar(line[i]);
line[i] = '\0';
}
}
p = 0;
flag = 0;
}
}
}
I imagine the problem is just that the HTML contains at least one line that is more than MAXLINE characters long. You don't check anywhere whether you're about to exceed the size of the array; if you do, you would indeed smash the stack. Your while loop could check whether p was less than MAXLINE, print a message if not, and stop. You couldn't do anything else without fairly significant changes to your program.

Resources