Here was my original code:
#include <stdio.h>
#define IN 1 // inside a word
#define OUT 0 // outside a word
// program to print input one word per line
int main(void)
{
int c, state;
state = OUT;
while ((c = getchar()) != EOF) {
if (c == ' ' || c == '\n' || c == '\t') {
state = OUT;
printf("\n");
}
else if (state == OUT) {
state = IN;
}
if (state == IN) {
putchar(c);
}
}
return 0;
}
But the problem was if there were multiple blanks (spaces) or multiple tabs next to each other a newline would be printed for both. So I used a variable (last) to keep track of where I was:
#include <stdio.h>
#define IN 1 // inside a word
#define OUT 0 // outside a word
// program to print input one word per line, corrected bug if there was
// more than one space between words to only print one \n
int main(void)
{
int c, last, state;
last = EOF;
state = OUT;
while ((c = getchar()) != EOF) {
if (c == ' ' || c == '\n' || c == '\t') {
if (last != c) {
state = OUT;
printf("\n");
}
}
else if (state == OUT) {
state = IN;
}
if (state == IN) {
putchar(c);
}
last = c;
}
return 0;
}
That solved it, except now if there is [blank][tab] next to each other, a newline gets printed for both.
Could someone please help?
Your problem with your original code is that you will output your newline for every whitespace character. You only want to do it when transitioning from word to non-word:
Change:
if (c == ' ' || c == '\n' || c == '\t') {
state = OUT;
printf("\n");
}
to:
if (c == ' ' || c == '\n' || c == '\t') {
if (state == IN) printf("\n");
state = OUT;
}
In fact, what I originally thought I'd suggest would be an enumeration for the states along the lines of:
enum eState {IN, OUT};
:
enum eState state = OUT;
but, for a simple finite state machine with only two states, you can just use an boolean:
#include <stdio.h>
#define FALSE (1==0)
#define TRUE (1==1)
// Or: enum eBoolean {FALSE = 0, TRUE = 1};
int main (void) {
int ch;
int inWord = FALSE; // Or: enum eBoolean inWord = FALSE;
// Process every character.
while ((ch = getchar()) != EOF) {
// Check for whitespace.
if (ch == ' ' || ch == '\n' || ch == '\t') {
// Check if transitioning nonwhite to white.
if (inWord) {
printf("\n");
}
// Mark white no matter what.
inWord = FALSE;
} else {
// Mark non whitespace.
inWord = TRUE;
}
// If not whitespace, output character.
if (inWord) {
putchar(ch);
}
}
return 0;
}
As paxdiablo said, your program is a typical finite state automata (FSA). You have to print a new line in transitions from state OUT to state IN and only then.
Below is how I would write such code. In this particular case it can be made simpler, but the structure is interesting because typical and it applies to any FSA. You have a big external switch with a case for each state. Inside each case, you get another one that materialize transitions, here transition event are input characters. All is left to do is think about what should be done for each transition. Also this structure is quite efficient.
You should keep it in mind, it's really a very common one to have in your toolkit of pre-thought program structures. I certainly do it.
#include <stdio.h>
#define IN 1 // inside a word
#define OUT 0 // outside a word
// program to print input one word per line
int main(void)
{
int c, state;
state = OUT;
while ((c = getchar()) != EOF) {
switch (state){
case OUT:
switch (c){
case ' ': case '\n': case '\t':
break;
default:
putchar(c);
state = IN;
}
break;
case IN:
switch (c){
case ' ': case '\n': case '\t':
putchar('\n');
state = OUT;
break;
default:
putchar(c);
}
break;
}
}
return 0;
}
See when you check in your second code
if (last != c) {
You are not checking for all conditions.last could be equal to space, tab or new line. In all such cases it should not print new line. Lets call the set of these three special characters as X.
Now when printing new line, you need to make sure that last character printed does not bring to set X. But you check that last!=current. Now current could be space, tab or new line. But it is only one value. It does not serve our need, our purpose.
So instead replace it with
if (last != ' ' && last != '\n' && last != '\t' ) {
You can see the code here:
#include <stdio.h>
#define IN 1 // inside a word
#define OUT 0 // outside a word
// program to print input one word per line, corrected bug if there was
// more than one space between words to only print one \n
int main(void)
{
int c, last, state;
last = 0; // We need it to make sure that a newline is not printed in case first
// char is space, tab or new line.
state = OUT;
while ((c = getchar()) != EOF) {
if (c == ' ' || c == '\n' || c == '\t') {
// if (last != c)
if (last != ' ' && last != '\n' && last != '\t' && last != 0 )
{
state = OUT;
printf("\n");
}
} else if (state == OUT) {
state = IN;
}
if (state == IN) {
putchar(c);
}
last = c;
}
return 0;
}
Edit
Fixed the bug paxdiablo pointed out in comments.
#include<stdio.h>
#define OFF 0
#define ON 1
main()
{
int c,state=ON;
while((c=getchar())!=EOF)
{
if(c=='\n'||c==' '||c=='\t')
{
if(state==OFF)putchar('\n');
state=ON;
}
else if(state==ON)
{
putchar(c);
state=OFF;
}
else if(state==OFF)
{
putchar(c);
}
}
}
Here's one way of approaching the problem, which was used above:
Where, STE=Space, tab or enter.
<STE><WORD>---->TYPE<WORD>
<STE><STE>----->DO NOTHING
<WORD><SPACE>-->TYPE<WORD><ENTER/NEWLINE>
<WORD><WORD>--->TYPE<WORD>
You can replace and with ON and OFF, as illustrated above.
Related
I've been doing some exercises from the "The C Programming language" (second edition), and I'm at 1-23, where you need to develop a program that strips out the comments.
This what I have so far:
#include <stdio.h>
#define CODE 0
#define START_COMMENT 1
#define END_COMMENT 2
#define COMMENT 3
#define INQUOTE 4
/* this is a test */
/* this is a *** comment maybe / but still testing */
main() {
char c;
char state=CODE;
while ((c = getchar()) != EOF) {
if(state == CODE) {
if (c == '/') {
state = START_COMMENT; /* this works? */
}
else if (c == '"' || c == '\'') {
state = INQUOTE;
putchar(c);
}
else {
putchar(c);
}
}
else if(state == INQUOTE) {
if (c == '"' || c == '\'') {
state = CODE;
putchar(c);
}
else {
putchar(c);
}
}
else if(state == START_COMMENT) {
if (c == '*') {
state = COMMENT;
}
else {
putchar('/');
putchar(c);
state = CODE;
}
}
else if(state == COMMENT) {
if (c == '*') {
state = END_COMMENT;
}
}
else if(state == END_COMMENT) {
if (c == '/') {
state = CODE;
}
else
state = COMMENT;
}
}
}
I'm using CLion on Mac, and it complains that line 54 always evaluates to "true". Which is this line at the bottom:
else if(state == END_COMMENT) {
Despite this remark, the program seems to work so far...
Does that line always evaluates to true, and if so, why? Because I don't see anything wrong with it.
As stated in the comments, this is much easier to debug as a switch statement. I converted it to a switch and the issues with the final if/else conditions went away.
I also am using CLion on a mac and saw the warnings that you were seeing.
Despite the comments above, your code handles the c style '/* .... */ comments correctly.
I think it is helpful to let people know that this a preprocessor that simply strips old-style c comments /*..*/ not //... from code and then puts out the stripped code.
The state machine is MUCH easier to read as a switch statement, and easier to debug as well.
Note that in one place, you were checking for one of two characters, which allowed the fallthrough style in one of the switch statements.
Sometimes, when it is easier to write the code more 'simply' rather than to figure out why the compiler feels that a condition will always be true, it is best to follow best practices and simplify.
#include <stdio.h>
const char CODE = 0;
const char START_COMMENT = 1;
const char END_COMMENT = 2;
const char COMMENT = 3;
const char INQUOTE = 4;
// Preprocessor which discards comments
int main() {
int c;
char state = CODE;
while (EOF != (c = getchar())) {
switch (state) {
case CODE:
switch (c) {
case '/': // If we are in a comment, we will strip this section of the code
// check if this is the start of a comment:
state = POTENTIAL_COMMENT;
break;
case '"':
case '\'':
state = INQUOTE;
putchar(c);
break;
default:
putchar(c);
}
break;
case INQUOTE:
if (c == '"' || c == '\'') {
state = CODE;
}
putchar(c);
break;
case POTENTIAL_COMMENT:
switch (c) {
case '*': // We saw the '/', so now we se the '*' and we are in a comment, just eat the char
state = COMMENT;
break;
case '/':
state = LINE_COMMENT;
break;
default:
putchar('/'); // we saw a '/' before, but it wasn't really the start of a comment, so put the '/' back and the current char
putchar(c);
state = CODE;
}
case COMMENT:
if (c == '*') {
state = END_COMMENT;
}
break;
case LINE_COMMENT:
if (c == '\n')
state = CODE;
break;
case END_COMMENT:
if (c == '/') {
state = CODE;
} else
state = COMMENT;
}
}
}
I'm trying to write a program that takes from the standard input stream a sentence, and based on the definition that a word is everything that is between "spaces"; "spaces" being the space character, tab character or newline character, so, for example, if the input stream is hey there this is some test, the output should be
hey
there
this
is
some
test
Here is my try:
#include <stdio.h>
#define TRUE 1
#define FALSE 0
#define IS_SPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
int main() {
for(int c, inWord = FALSE; (c = getchar()) != EOF;)
if(!IS_SPACE(c)) {
putchar(c);
inWord = TRUE;
}
else if(inWord) {
putchar('\n');
inWord = FALSE;
}
return 0;
}
But I don't like this approach because I am manually entering TRUE and FALSE to inWord when it can be automatically be done by inWord = !IS_SPACE(c), but I don't know how to modify the code to make just one call to IS_SPACE without creating another temporal variable.
The bug is that it doesn't print the last '\n' if the text ends with nonspace. Or maybe it is a feature? I did not fix it.
As to your question, you may do
for(int c, inWord=FALSE; (c = getchar()) != EOF;) {
if(!IS_SPACE(c))
putchar(c);
else if(inWord)
putchar('\n');
inword = !IS_SPACE(c);
}
or even
for(int c, bPrevInWord = FALSE; (c = getchar()) != EOF;) {
int bInWord = !IS_SPACE(c);
if(bInWord)
putchar(c);
else if(bPrevInWord)
putchar('\n');
bPrevInWord = bInWord;
}
int my_spaces[256] = { 0 };
my_spaces[' '] = my_spaces['\t'] = my_spaces['\n'] = 1;
#define MY_SPACE(c) (my_sapces[c])
This is the core of how isspace() and friends are often implemented but with bits for isspace(), isprint(), ....
Old answer before your edit:
Look at strtok, though strtok_r is now my function of choice. Being built into C you can expect it to be optimized for the current implementation.
I am asked to squeezed two or more consecutive blank lines in the input as one blank line in the output. So I have to use Cygwin to do I/O or test it.
Example: ./Lab < test1.txt > test2.txt
my code is:
int main(void){
format();
printf("\n");
return 0;
}
void format(){
int c;
size_t nlines = 1;
size_t nspace = 0;
int spaceCheck = ' ';
while (( c= getchar()) != EOF ){
/*TABS*/
if(c == '\t'){
c = ' ';
}
/*SPACES*/
if (c ==' '){/*changed from isspace(c) to c==' ' because isspace is true for spaces/tabs/newlines*/
/* while (isspace(c = getchar())); it counts while there is space we will put one space only */
if(nspace > 0){
continue;
}
else{
putchar(c);
nspace++;
nlines = 0;
}
}
/*NEW LINE*/
else if(c == '\n'){
if(nlines >0){
continue;
}
else{
putchar(c);
nlines++;
nspace = 0;
}
}
else{
putchar(c);
nspace = 0;
nlines = 0;
}
}
}
However my test2.txt doesn't have the result I want. Is there something wrong in my logic/code?
You provide too little code, the interesting part would be the loop around the code you posted...
What you actually have to do there is skipping the output:
FILE* file = ...;
char c, prev = 0;
while((c = fgets(file)) != EOF)
{
if(c != '\n' || prev != '\n')
putchar(c);
prev = c;
}
If we have an empty line following another one, then we encounter two subsequent newline characters, so both c and prev are equal to '\n', which is the situation we do not want to output c (the subsequent newline) – and the inverse situation is any one of both being unequal to '\n', as you see above – and only then you want to output your character...
Side note: prev = 0 – well, I need to initalise it to anything different than a newline, could as well have been 's' – unless, of course, you want to skip an initial empty line, too, then you would have to initialise it with '\n'...
Edit, referring to your modified code: Edit2 (removed references to code as it changed again)
As your modified code shows that you do not only want to condense blank lines, but whitespace, too, you first have to consider that you have two classes of white space, on one hand, the newlines, on the other, any others. So you have to differentiate appropriately.
I recommend now using some kind of state machine:
#define OTH 0
#define WS 1
#define NL1 2
#define NL2 3
int state = OTH;
while (( c= getchar()) != EOF )
{
// first, the new lines:
if(c == '\n')
{
if(state != NL2)
{
putchar('\n');
state = state == NL1 ? NL2 : NL1;
}
}
// then, any other whitespace
else if(isspace(c))
{
if(state != WS)
{
putchar(' ');
state = WS;
}
}
// finally, all remaining characters
else
{
putchar(c);
state = OTH;
}
}
First differentiation occurs to the current character's own class (newline, whitespace or other), second differentiation according to the previous character's class, which defines the current state. Output occurs always for any non-whitespace character or if the two subsequent whitespace characters only, if they are of different class (newline is a little specific, I need two states for, as we want to leave one blank line, which means we need two subsequent newline characters...).
Be aware: whitespace only lines do not apply as blank lines in above algorithm, so they won't be eliminated (but reduced to a line containing one single space). From the code you posted, I assume this is intended...
For completeness: This is a variant removing leading and trailing whitespace entirely and counting whitespace-only lines as empty lines:
if(c == '\n')
{
if(state != NL2)
{
putchar('\n');
state = state == NL1 ? NL2 : NL1;
}
}
else if(isspace(c))
{
if(state == OTH)
state = WS;
}
else
{
if(state == WS)
{
putchar('');
}
putchar(c);
state = OTH;
}
Secret: Only enter the whitespace state, if there was a non-ws character before, but print the space character not before you encounter the next non-whitespace.
Coming to the newlines - well, if there was a normal character, we are either in state OTH or WS, but none of the two NL states. If there was only whitespace on the line, the state is not modified, thus we remain in the corresponding NL state (1 or 2) and skip the line correspondingly...
To dissect this:
if(c == '\n') {
nlines++;
is nlines ever reset to zero?
if(nlines > 1){
c = '\n';
And what happens on the third \n in sequence? will nlines > 1 be true? Think about it!
}
}
putchar(c);
I don't get this: You unconditionally output your character anyways, defeating the whole purpose of checking whether it's a newline.
A correct solution would set a flag when c is a newline and not output anything. Then, when c is NOT a newline (else branch), output ONE newline if your flag is set and reset the flag. I leave the code writing to you now :)
This was my first time posting so i apologize for poor format and or any unreasonable questions.
So i have been working on the "remove comments" program for some time and made progress but very minimal. I am new to C so I'm writing it using some basic functions and skills. The input file for the code does not require any functions to be read but instead is passed to the program using < in the terminal.
The text file that I'm using contains the following:
some/* crazy */stuff
some/* crazy */ stuff
some/*crazy /*crazy*/*/stuff
"some /* crazy */ stuff "
some/* "crazy" */ stuff
some/* crazy stuff
To test the different comment formats.
The code i have so far is:
#include <stdio.h>
#define IN_COMMENT 1
int main(int argc, char **argv)
{
int c;
while ((c=getchar())!=EOF)
{
if(c=='/'&&getchar()=='*')
{
while(c!='*' && getchar()!='/')
{
c = " ";
c= getchar();
}
}
if(c=='"')
{
c=getchar();
while(c!='"')
{
putchar(c);
c=getchar();
}
putchar(c);
}
}
putchar(c);
printf("done.\n");
return 0;
}
The thing is that i cannot figure out a way to set up a condition that would print out an error message when there is a case in which the comment is started but never closed, such as (some/* crazy stuff)
Another problem is that i cant seem to find the bug which when i run my program and input the text file omits the *, so when i input :
some/* crazy */stuff
some/* crazy */ stuff
some/*crazy /*crazy*/*/stuff
"some /* crazy */ stuff "
some/* "crazy" */ stuff
i end up getting the following:
some*stuff
some* stuff
some**/tuff
"some /* crazy */ stuff "
some* stuff
I cant figure out a way to fix the two issues. The professor suggested a different way of writing the program by defining different states, but when i tried that it was even more confusing.
Your description is focusing on the difference between operating on a stream and operating on a buffer. In both C and Java either technique is possible.
Here your task is to do the job in a stream situation, i.e. you cannot "look ahead" and you cannot "write backwards" - all you can do is retrieve the next character, update some variables if appropriate, and decide whether or not to output that character.
This is called a state machine; your main loop will read a character and then take different action based on what state your variables were in.
To get you started, you're going to need to store at least the following:
whether you are in a comment or not
If you're not in a comment, then whether you just read a /.
For example, if the latter state is set and you get a '*' then you would set the former state (and reset the latter).
Well, usual solution to this kind of problem is to make FSM. So, just make number of states and deаfine how each next letter will affect state, due to current state. Smth like
//#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
//#include <conio.h>
#include <string.h>
typedef enum states {
CODE,
HASH_START,
STAR_END,
COMMENT
} states;
void main() {
FILE *input = NULL;
char c;
states state;
state = CODE;
input = fopen("C:/c/code.txt", "r");
if (input == NULL) {
exit(EXIT_FAILURE);
}
while (fscanf(input, "%c", &c) == 1) {
switch (c) {
case '/' :
switch (state) {
case CODE:
state = HASH_START;
break;
case STAR_END:
//a bit ugly here, but require less states. You can omit read next
//if use more states
fscanf(input, "%c", &c);
state = CODE;
break;
}
break;
case '*' :
switch (state) {
case HASH_START:
state = COMMENT;
break;
case COMMENT:
state = STAR_END;
break;
}
break;
default:
if (state == HASH_START) {
state = CODE;
}
}
if (state == CODE) {
printf("%c", c);
}
}
//_getch();
}
this code deletes only /**/. Write bigger diagram and complete code.
#include <stdio.h>
#if 0
Description :
To delete a comment by entering the C source from standard input.
// To delete a line break up (newline remain)
/**/ To allow the nest (standard does not allow)
also replaced with a single space(The request by the standard)
#endif
int main(void){
FILE *fp = stdin;
int ch, chn;
int nest_level=0;
#if 0
in_range_comment : /* this */
in_line_comment : //this
in_string : "this"
in_char_constnt : ' '
#endif
enum { none, in_line_comment, in_range_comment, in_string, in_char_constant } status;
status = none;
while(EOF!=(ch=fgetc(fp))){
switch(status){
case in_line_comment :
if(ch == '\n'){
status = none;
putchar(ch);
}
continue;
case in_range_comment :
if(ch == '*'){
chn = fgetc(fp);
if(chn == '/'){
if(--nest_level == 0){
status = none;
putchar(' ');
}
continue;
}
ungetc(chn, fp);
} else if(ch == '/'){
chn = fgetc(fp);
if(chn == '*'){
++nest_level;
continue;
}
ungetc(chn, fp);
}
continue;
case in_string :
if(ch == '\\'){
putchar(ch);
chn = fgetc(fp);
if(chn == '"'){
putchar(chn);
continue;
}
ungetc(chn, fp);
} else {
if(ch == '"')
status = none;
putchar(ch);
}
continue;
case in_char_constant :
if(ch == '\\'){
putchar(ch);
chn = fgetc(fp);
if(chn == '\''){
putchar(chn);
continue;
}
ungetc(chn, fp);
} else {
if(ch == '\'')
status = none;
putchar(ch);
}
continue;
case none :
switch(ch){
case '/':
if('/' == (chn = fgetc(fp))){
status = in_line_comment;
continue;
} else if('*' == chn){
status = in_range_comment;
++nest_level;
continue;
} else
ungetc(chn, fp);
putchar(ch);
break;
case '"':
status = in_string;
putchar(ch);
break;
case '\'':
status = in_char_constant;
putchar(ch);
break;
default:
putchar(ch);
}
}
}
return 0;
}
I have written the following program to answer Kernighan and Ritchies ch1 problem 12.
The issue is that I have never really understood how to properly use functions and would like to know why the one I wrote into this program, getcharc(), does not work?
What are good resources that explain correct function usage. Where? and How?
I know the optimal solution to this problem from Richard Heathfield's site (which uses || or, rather than nested while statements, which I have used), however I would like to know how to make my program work properly:
#include <stdio.h>
int getcharc ();
// Exercise 1-12
// Copy input to output, one word per line
// words deleniated by tab, backspace, \ and space
int main()
{
int c;
while ((c = getchar()) != EOF) {
while ( c == '\t') {
getcharc(c);
}
while ( c == '\b') {
getcharc(c);
}
while ( c == '\\') {
getcharc(c);
}
while ( c == ' ') {
getcharc(c);
}
putchar(c);
}
}
int getcharc ()
{
int c;
c = getchar();
printf("\n");
return 0;
}
The original program (and I know it has bugs), without the function was:
#include <stdio.h>
// Exercise 1-12
// Copy input to output, one word per line
// words deleniated by tab, backspace, \ and space
int main()
{
int c;
while ((c = getchar()) != EOF) {
while ( c == '\t') {
c = getchar();
printf("\n");
}
while ( c == '\b') {
c = getchar();
printf("\n");
}
while ( c == '\\') {
c = getchar();
printf("\n");
}
while ( c == ' ') {
c = getchar();
printf("\n");
}
putchar(c);
}
}
So all I am trying to do with the function is to stop
c = getchar();
printf("\n");
being repeated every time.
What, exactly, is this getcharc() function supposed to do? What it does, is read a character from input, print a newline, and return zero. The character just read from input is discarded, because you didn't do anything with it. When it's called, the return value is ignored as well. In each of the places where it is called, you're calling it in an infinite loop, because there's no provision made for changing the loop control variable.
Perhaps you were intending something like c = getcharc(), but that wouldn't really help because you aren't returning c from the function, anyway. (Well, it would help with the "infinite loop" part, anyway.)
What's the point of this function anyway? If you just use getchar() correctly in its place, it looks like you'd have your solution, barring a few other bugs.
One of the possible solution is, change prototype for your function to int getcharc (int c, int flag).
Now your code after some modification;
#include <stdio.h>
int getcharc (int c, int flag);
// Exercise 1-12
// Copy input to output, one word per line
// words deleniated by tab, backspace, \ and space
int main()
{
int c;
int flag = 0; //to keep track of repeated newline chars.
while ((c = getchar()) != '\n') {
flag = getcharc(c, flag); // call getcharc() for each char in the input string. Testing for newline and printing of chars be done in the getcharc() function
}
return 0;
}
int getcharc (int c, int flag)
{
if( (c == ' ' || c == '\t' || c == '\b' || c== '\\') && flag == 0)
{
printf("\n");
flag = 1;
}
else
{
if(c != ' ' && c != '\t' && c != '\b' && c!= '\\')
{
putchar(c);
flag = 0;
}
}
return flag;
}
EDIT:
but I wanted to keep the nested while statements rather than using || or
Your nested while loop is executing only once for each character as grtchar() reads one character at one time. No need of nested loops here! You can check it by replacing while to if and your code will give the same output for a given string. See the output here.
know the optimal solution to this problem from Richard Heathfield's site (which uses || or, rather than nested while statements, which I have used), however I would like to know how to make my program work properly:
You make your program work to some extent (with your bugs) by adding an if condition and a break statement as;
#include <stdio.h>
int getcharc (int c);
int main()
{
int c;
while ((c = getchar()) != '\n') {
while ( c == '\t') {
c = getcharc(c);
if(c != '\t')
break;
}
....
....
while ( c == ' ') {
c = getcharc(c);
if(c != ' ')
break;
}
putchar(c);
}
return 0;
}
int getcharc (int c)
{
c = getchar();
printf("\n");
return c;
}
// compiled by my brain muhahaha
#include <stdio.h>
int getcharc(); // we prototype getcharc without an argument
int main()
{
int c; // we declare c
// read character from stdio, if end of file quit, store read character in c
while ((c = getchar()) != EOF) {
// if c is tab \t call function getcharc() until forever since c never changes
while ( c == '\t') {
getcharc(c); // we call function getcharc with an argument
// however getcharc doesn't take an argument according to the prototype
}
// if c is \b call function getcharc() until forever since c never changes
while ( c == '\b') {
getcharc(c);
}
// if c is \\ call function getcharc() until forever since c never changes
while ( c == '\\') {
getcharc(c);
}
// if c is ' ' call function getcharc() until forever since c never changes
while ( c == ' ') {
getcharc(c);
}
// since we never will get here but if we happened to get here by some
// strange influence of some rare cosmic phenomena print out c
putchar(c);
}
}
// getcharc doesn't take an argument
int getcharc ()
{
int c; // we declare another c
c = getchar(); // we read from the keyboard a character
printf("\n"); // we print a newline
return 0; // we return 0 which anyway will never be read by anyone
}
maybe you are getting confused with the old K&R
nowadays when you write a function argument you specify it like
int getcharch(int c)
{
...
}