How do I get a program using getchar to run? - c

I'm a total C n00b trying to teach myself C off K&R. My question is kind of embarrassingly elementary. OK, here goes: I can't get programs using getchar to give the kind of output I expected. If you happen to have K&R on hand, I'm stuck on exercise 1.13. The question goes, "Write a program to print a histogram of the lengths of words in its input. " and I can't even tackle the horizontal version because of this issue I'm having.
I'm on XP using Dev-C++ (mingW compiler) and running programs off the command line. My issue is, when I try to run my program, it waits for me to enter characters to scan from, but when I'm done inputting and hit Enter, it doesn't do anything. I expect it to go ahead and print the histogram as I expected. In reality, it doesn't even seem to count up word lengths, because as you can see in the code, when I try to print what's in the ctr array just to see if it contains anything, nothing prints.
I'm so n00b that I have no idea if it's my code or the command line that's at fault. But I suspect it's something with the system, because when I try to compile and run a model program, the same thing happens. Type in input, hit Enter, nothing happens. If I Ctrl-C, sometimes it spits out an asterisk or two that looks nothing like the model output. Other times, it doesn't do anything (just goes right back to the prompt).
Here's my code for the exercise. I've spent an entire day on this and am questioning my ability to carry on with programming. I'd really, really appreciate it if anyone could get me out of this hole!
Also, I have another question about the model program I mentioned above, but I think I should post it in its own question. Thanks all :)
#include <stdio.h>
//#define 1 IN
//#define 0 OUT
int main () {
//start w/ state = OUT
int c = 0;
// int state = OUT;
int len = 0;
int ctr[12];
int i, j;
i = j = 0;
for (i = 0; i <12; i++)
ctr[i] = 0;
while ((c = getchar()) != EOF)
if (c != ' ' && c != '\t' && c != '\n') {
// state = IN;
len++;
printf("%d", len);
}
else {
ctr[len]++;
len = 0;
}
for (i = 0; i <12; i++)
printf("%d\n", ctr[i]);
for (i = 0; i <12; i++) {
printf("%d\n", i);
for (j = 0; j <= ctr[i]; j++)
printf("-");
printf("\n");
}
return 0;
}

Your while loop is looking for EOF which stands for end-of-file, not end-of-line.
On Windows, you need to type ctrl-z to simulate end-of-file.

It doesn't look like you're actually storing c (your input) anywhere... nor printing it. You're printing the size of the string, but not the actual characters. If you ctr[i] = c; somewhere (that's you adding the character to the array), and then print the array, you'll see your input. Oh and yes, the answer about ctrl-z is also important.
Also, if you're totally new to the language, I would strongly urge you to put brackets around your while content. It's going to be a while before you can just glance at the code and know what will fall into the purview of the while loop and what will not if you don't have braces around it.

I didn't see anything really wrong with the code, so I loaded it up under gcc and it seems to work fine, as long as you remember that you have to put in an EOF (CTRL-D) to terminate the while loop. I entered 4 lines and while I can't make any statements about the correctness of the answers, each time I hit enter I got a series of numbers equal to the number of characters I entered, followed by a space. This is exactly what your code says to do.
When I entered the CTRL-D, I got the summary information. Again, I'm not going to make any statements about the correctness of the output, but I did get two major sections as described in your code.

Related

How to use fgetc() to capture only letters and storing input to an array

I am trying to write an indexing program where it will take input from the user and store it into an array then keep counting the occurrence of words for example.
user enters: hello##world I,I,I am##!stuck201
hello 1 occurred 1 time
world 1 occurred 1 time
I occurred 3 times
am occurred 1 time
stuck occurred 1 time
So as you can see it will count anything that contains letter(s) separated by anything as a word.
(I am confused on how to go about checking the input for anything other than letters, I was thinking of using ASCII codes but there has to be a better way, if you could just set me in the correct direction for this, Thank you much.)
Before I began the program I was trying to get I/O working and I am having difficulty. The actual program will require me to use 2 dimensional arrays, but if you could help me with this snippet of code that will be appreciated thanks.
#include <stdio.h>
int main()
{
char array[64];
int i=0, j, input;
printf("Please enter an input:");
input==fgetc(stdin);
while(input != " ")
{
array[i]==input;
i++;
input==fgetc(stdin);
}
for(j=0;j<10;j++)
{
printf("You entered:%c",array[j]);
}
}
Upon compilation it gives me a warning "12:14 warning: comparison between pointer and integer"
Output of this code:::
Please enter an input: (I type input) ehehasd world hello (enter)
then it just sits at blank cursor and I have to exit using CTRL C
I want this snippet of code to just take input from user that is separated by a space store it into an array then print out what the user entered. What am I doing wrong?
Check isalpha, it has some fineprints about what it will consider a letter, but it may work for your case.
Another way to do it, if you don't want to do the loop yourself is to use regular expressions. It is fairly easy to make a regex that returns only sequences of letters.
The line (which appears twice in the code):
input==fgetc(stdin);
makes a comparison, not an assignment. Use:
input = fgetc(stdin);
Your line:
while(input != " ")
is incorrect and is the source of the compiler warning. You are comparing a string with a character. You probably intended to use:
while (input != ' ')
and since you could encounter EOF, you probably should use:
while (input != EOF && input != ' ')
You could sensibly use #include <ctype.h> and then:
while (isalpha(input))
which automatically handles EOF (it's a valid input to isalpha(), but returns false; EOF is not an alphabetic character).
Your final loop should probably be:
for (int j = 0; j < i; j++)
(assuming you have a C99 or more recent compiler — if not, declare j outside the loop as now). This only outputs words that have been entered. Otherwise, you'll be printing undefined gibberish.
You'll need to upgrade the code to handle multiple words in the input. At the moment, it stops at the end of the first word (assuming you fix the other problems that I've identified).
Use isAlpha() to test is it is a letter, look here

K&R programming exercise 8

Alright, so I'm doing exercise 8 in K&R second edition. Upon looking up the answer after my attempt at doing the exercise didn't print anything but the newlines (the other ints for tabs and empty spaces remained 0 despite running loops to count - I later found out that I used the wrong character for blank space which is just a blank space but it still neglected to count '\t' correctly), I found this:
#include <stdio.h>
int main(void)
{
int blanks, tabs, newlines;
int c;
int done = 0;
int lastchar = 0;
blanks = 0;
tabs = 0;
newlines = 0;
while(done == 0)
{
c = getchar();
if(c == ' ')
++blanks;
if(c == '\t')
++tabs;
if(c == '\n')
++newlines;
if(c == EOF)
{
if(lastchar != '\n')
{
++newlines;
}
done = 1;
}
lastchar = c;
}
printf("Blanks: %d\nTabs: %d\nLines: %d\n", blanks, tabs, newlines);
return 0;
}
Now this works fine. K&R is interesting in that it uses ideas not taught to you in the actual text, for instance I tried to run my "while" loop with multiple IFs the same way this one does, except my WHILE loop ran only when getchar was != EOF. I want to know why it didn't work that way.
I found that what they did is a much better idea, creating the int done and then assigning it a 1 instead of 0 at the end of the program was a much better idea, but mine still ran somewhat correctly. (sorry I don't have my own original code this time).
Where I am stumped is what is the purpose of main(void) and return 0;? Before starting this book I found criticism on this but readers claimed it was only in the 1st edition. Here I find that the 2nd edition doesn't teach that but then puts it in the solutions text.
Also, what is the purpose of the int "lastchar"? If getchar(c) is the input and lastchar is always defined as 0, then how could lastchar possibly be changed by any input whatsoever to make it meaningful to the program at all by running a loop to count newlines with it? I see that lastchar is defined as 'c' at the end of the program, but how does that pertain to it being called previously?
Sorry if any of my questions are complicated. Please just answer whatever you can and let me know if you need any further clarification. Just to reiterate I'm very curious why the program can't run a while loop using getchar(c) != EOF, with the same IF statements. Rather than using while done == 0. I feel as if it could be a little shorter/concise (definitely can't say simpler) that way.
Where I am stumped is what is the purpose of main(void) and return 0;?
In standard C programs, main(0) should return an int, and 0 indicates successful program completion. One could argue that main should have two parameters -- the command-line argument count and an array of arguments, but if your program doesn't make use of arguments then it isn't necessary.
Also, what is the purpose of the int "lastchar"?
And the end of the while loop, the program stores a copy of the current character in the lastchar variable. As you can see in the EOF-handling code, it makes use of lastchar when determining whether the input text ended in a partial line.
I'm very curious why the program can't run a while loop using getchar(c) != EOF, with the same IF statements.
You could code it that way, but the conditional for the while can appear confusing to someone who doesn't have a lot of experience with C: while ((c = getchar()) != EOF). You would also have to move the if (lastchar != '\n') ++newlines; to just outside of the while loop.
Maybe you should make that change to the program and compare it's output to the original for various types of input (empty file, file ending with a newline, file not ending with a newline). Do both programs show the same output? If not, why? Does the modified version still seem more concise? Which would be easier to make changes to in the future?
Many decisions go into a choice of how to structure a program. Even one as simple as this K&R example.

Flushing stdin after every input - which approach is not buggy?

After Mark Lakata pointed out that the garbage isn't properly defined in my question I came up with this. I'll keep this updated to avoid confusions.
I am trying to get a function that I can call before a prompt for user input like printf("Enter your choice:); followed a scanf and be sure that only the things entered after the prompt would be scanned in by scanf as valid input.
As far as I can understand the function that is needed is something that flushes standard input completely. That is what I want. So for the purpose of this function the "garbage" is everything in user input i.e. the whole user input before that user prompt.
While using scanf() in C there is always the problem of extra input lying in the input buffer. So I was looking for a function that I call after every scanf call to remedy this problem. I used this, this, this and this to get these answers
//First approach
scanf("%*[^\n]\n");
//2ndapproach
scanf("%*[^\n]%*c");
//3rd approach
int c;
while((c = getchar()) != EOF)
if (c == '\n')
break;
All three are working as far as I could find by hit-and-trial and going by the references. But before using any of these in all of my codes I wanted to know whether any of these have any bugs?
EDIT:
Thanks to Mark Lakata for one bug in 3rd. I corrected it in the question.
EDIT2:
After Jerry Coffin answered I tested the 1st 2 approaches using this program in code:blocks IDE 12.11 using GNU GCC Compiler(Version not stated in the compiler settings).
#include<stdio.h>
int main()
{
int x = 3; //Some arbitrary value
//1st one
scanf("%*[^\n]\n");
scanf("%d", &x);
printf("%d\n", x);
x = 3;
//2nd one
scanf("%*[^\n]%*c");
scanf("%d", &x);
printf("%d", x);
}
I used the following 2 inputs
First Test Input (2 Newlines but no spaces in the middle of garbage input)
abhabdjasxd
23
bbhvdahdbkajdnalkalkd
46
For the first I got the following output by the printf statements
23
46
i.e. both codes worked properly.
Second Test input: (2 Newlines with spaces in the middle of garbage input)
hahasjbas asasadlk
23
manbdjas sadjadja a
46
For the second I got the following output by the printf statements
23
3
Hence I found that the second one won't be taking care of extra garbage input whitespaces. Hence, it isn't foolproof against garbage input.
I decided to try out a 3rd test case (garbage includes newline before and after the non-whitespace character)
``
hahasjbas asasadlk
23
manbdjas sadjadja a
46
The answer was
3
3
i.e. both failed in this test case.
The first two are subtly different: they both read and ignore all the characters up to a new-line. Then the first skips all consecutive white space so after it executes, the next character you read will be non-whitespace.
The second reads and ignores characters until it encounters a new-line then reads (and discards) exactly one more character.
The difference will show up if you have (for example) double-spaced text, like:
line 1
line 2
Let's assume you read to somewhere in the middle of line 1. If you then execute the first one, the next character you read in will be the 'l' on line 2. If you execute the second, the next character you read in will be the new-line between line 1 and line 2.
As for the third, if I were going to do this at all, I'd do something like:
int ch;
while ((ch=getchar()) != EOF && ch != '\n')
;
...and yes, this does work correctly -- && forces a sequence point, so its left operand is evaluated first. Then there's a sequence point. Then, if and only if the left operand evaluated to true, it evaluates its right operand.
As for performance differences: since you're dealing with I/O to start with, there's little reasonable question that all of these will always be I/O bound. Despite its apparent complexity, scanf (and company) are usually code that's been used and carefully optimized over years of use. In this case, the hand-rolled loop may be quite a bit slower (e.g., if the code for getchar doesn't get expanded inline) or it may be about the same speed. The only way it stands any chance of being significantly faster is if the person who wrote your standard library was incompetent.
As far maintainability: IMO, anybody who claims to know C should know the scan set conversion for scanf. This is neither new nor rocket science. Anybody who doesn't know it really isn't a competent C programmer.
The first 2 examples use a feature of scanf that I didn't even know existed, and I'm sure a lot of other people didn't know. Being able to support a feature in the future is important. Even if it was a well known feature, it will be less efficient and harder to read the format string than your 3rd example.
The third example looks fine.
(edit history: I made a mistake saying that ANSI-C did not guarantee left-to-right evaluation of && and proposed a change. However, ANSI-C does guarantee left-to-right evaluation of &&. I'm not sure about K&R C, but I can't find any reference to it and no one uses it anyways...)
Many other solutions have the problem that they cause the program to hang and wait for input when there is nothing left to flush. Waiting for EOF is wrong because you don't get that until the user closes the input completely!
On Linux, the following will do a non-blocking flush:
// flush any data from the internal buffers
fflush (stdin);
// read any data from the kernel buffers
char buffer[100];
while (-1 != recv (0, buffer, 100, MSG_DONTWAIT))
{
}
The Linux man page says that fflush on stdin is non-standard, but "Most other implementations behave the same as Linux."
The MSG_DONTWAIT flag is also non-standard (it causes recv to return immediately if there is no data to be delivered).
You should use getline/getchar:
#include <stdio.h>
int main()
{
int bytes_read;
int nbytes = 100;
char *my_string;
puts ("Please enter a line of text.");
/* These 2 lines are the heart of the program. */
my_string = (char *) malloc (nbytes + 1);
bytes_read = getline (&my_string, &nbytes, stdin);
if (bytes_read == -1)
{
puts ("ERROR!");
}
else
{
puts ("You typed:");
puts (my_string);
}
return 0;
I think if you see carefully at right hand side of this page you will see many questions similar to yours. You can use fflush() on windows.

File Reading in C, Random Error

Thank you everybody so far for your input and advice!
Additionally:
After testing and toying further, it seems individual calls to FileReader succeed. But calling FileReader multiple times (these might be separate versions of FileReader) causes the issue to occur.
End Add
Hello,
I have a very unusual problem [please read this fully: it's important] (Code::Blocks compiler, Windows Vista Home) [no replicable code] with the C File Reading functions (fread, fgetc). Now, normally, the File Reading functions load up the data correctly to a self-allocating and self-deallocating string (and it's not the string's issue), but this is where it gets bizarre (and where Quantum Physics fits in):
An error catching statement reports that EOF occurred too early (IE inside the comments section at the start of the text file it's loading). Printing out the string [after it's loaded] reports that indeed, it's too short (24 chars) (but it has enough space to fit it [~400] and no allocation issues). The fgetc loop iterator reports it's terminating at just 24 (the file is roughly 300 chars long) with an EOF: This is where it goes whacky:
Temporarily checking Read->_base reports the entire (~300) chars are loaded - no EOF at 24. Perplexed, [given it's an fgetc loop] I added a printf to display each char [as a %d so I could spot the -1 EOF] at every step so I could see what it was doing, and modified it so it was a single char. It loops fine, reaching the ~300 mark instead of 24 - but freezes up randomly moments later. BUT, when I removed printf, it terminated at 24 again and got caught by the error-catching statement.
Summary:
So, basically: I have a bug that is affected by the 'Observer Effect' out of quantum physics: When I try to observe the chars I get from fgetc via printf, the problem (early EOF termination at 24) disappears, but when I stop viewing it, the error-catch statement reports early termination.
The more bizarre thing is, this isn't the first time it's occurred. Fread had a similar problem, and I was unable to figure out why, and replaced it with the fgetc loop.
[Code can't really be supplied as the code base is 5 headers in size].
Snippet:
int X = 0;
int C = 0;
int I = 0;
while(Copy.Array[X] != EOF)
{
//Copy.Array[X] = fgetc(Read);
C = fgetc(Read);
Copy.Array[X] = C;
printf("%d %c\n",C,C); //Remove/add this as necessary
if(C == EOF){break;}
X++;
}
Side-Note: Breaking it down into the simplest format does not reproduce the error.
This is the oldest error in the book, kind of.
You can't use a variable of type char to read characters (!), since the EOF constant doesn't fit.
You need:
int C;
Also, the while condition looks scary, you are incrementing X in the loop, then checking the (new) position, is that properly initialized? You don't show how Copy.Array is set up before starting the loop.
I would suggest removing that altogether, it's very strange code.
In fact, I don't understand why you loop reading single characters at all, why not just use fread() to read as much as you need?
Firstly, unwind's answer is a valid point although I'm not sure whether it explains the issues you are seeing.
Secondly,
printf("%d %c\n",C,C); //Remove/add this as necessary
might be a problem. The %d and %c format specifiers expect an int to be the parameter, you are only passing a char. Depending on your compiler, this might mean that they are too small.
This is what I think the problem is:
How are you allocating Copy.Array? Are you making sure all its elements are zeroed before you start? If you malloc it (malloc just leaves whatever garbage was in the memory it returns) and an element just happens to contain 0xFF, your loop will exit prematurely because your while condition tests Copy.Array[X] before you have placed a character in that location.
This is one of the few cases where I allow myself to put an assignment in a condition because the pattern
int c;
while ((c = fgetc(fileStream)) != EOF)
{
doSomethingWithC(c);
}
is really common
Edit
Just read your "Additionally" comment. I think it is highly likely you are overrunning your output buffer. I think you should change your code to something like:
int X = 0; int C = 0; int I = 0;
while(X < arraySize && (C = fgetc(Read)) != EOF)
{
Copy.Array[X] = C;
printf("%d %c\n", (int)C, (int)C);
X++;
}
printf("\n");
Note that I am assuming that you have a variable called arraySize that is set to the number of characters you can write to the array without overrunning it. Note also, I am not writing the EOF to your array.
You probably have some heap corruption going on. Without seeing code it's impossible to say.
Not sure if this is your error but this code:
C = fgetc(Read);
Copy.Array[X] = C;
if(C == EOF){break;}
Means you are adding the EOF value into your array - I'm pretty sure you don't want to do that, especially as your array is presumably char and EOF is int, so you'll actually end up with some other value in there (which could mess up later loops etc).
Instead I suggest you change the order so C is only put in the array once you know it is not EOF:
C = fgetc(Read);
if(C == EOF){break;}
Copy.Array[X] = C;
Whilst this isn't what I'd call a 'complete' answer (as the bug remains), this does solve the 'observer effect' element: I found, for some reason, printf was somehow 'fixing' the code, and using std::cout seemed to (well, I can't say 'fix' the problem) prevent the observer effect happening. That is to say, use std::cout instead of printf (as printf is the origin of the observer effect).
It seems to me that printf does something in memory on a lower level that seems to partially correct what does indeed seem to be a memory allocation error.

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.

Resources