'if' statements not behaving as expected without 'else' - c

Just a quick question; I've been working through K&R and the code for the digit/whitespace/other counter works fine. However, whilst trying to get my head round the functionality of else I've encountered something which doesn't work as expected.
The code from the book is as follows:
#include <stdio.h>
/* count digits, white space, others */
main()
{
int c, i, nwhite, nother;
int ndigit[10];
nwhite = nother = 0;
for (i = 0; i < 10; ++i)
ndigit[i] = 0;
while ((c = getchar()) != EOF)
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
else if (c == ' ' || c == '\n' || c == '\t')
++nwhite;
else
++nother;
printf("digits =");
for (i = 0; i < 10; ++i)
printf(" %d", ndigit[i]);
printf(", white space = %d, other = %d\n", nwhite, nother);
}
If I then modify the while loop so it reads:
while ((c = getchar()) != EOF)
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
if (c == ' ' || c == '\n' || c == '\t')
++nwhite;
It should still have the same functionality as the original code except for the fact it won't count 'other' characters. However what I actually get is in fact just the 'digit' part working, with 'nwhite' returning zero no matter what the input. I feel the disparity is perhaps due to a fundamental misunderstanding of how if statements function.

while ((c = getchar()) != EOF)
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
if (c == ' ' || c == '\n' || c == '\t')
++nwhite;
The second if statement is no longer in the loop. Use { and } to enclose the loop statements.

while ((c = getchar()) != EOF)
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
if (c == ' ' || c == '\n' || c == '\t')
++nwhite;
Is equivalent to
while ((c = getchar()) != EOF) {
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
}
if (c == ' ' || c == '\n' || c == '\t')
++nwhite;
Only the first statement that follows a looping or branch construct "belongs" to that construct. That is why the original if-else if-else chain works without braces. Each statement chains to the previous with the first if/else statement belonging to the while loop and the second if/else belonging to the first if/else. It is idiomatic to express the logic this way to avoid unnecessary indenting.
It may help to visualize the code with braces
while ((c = getchar()) != EOF) {
if (c >= '0' && c <= '9') {
++ndigit[c-'0'];
}
else {
if (c == ' ' || c == '\n' || c == '\t') {
++nwhite;
}
else {
++nother;
}
}
}

Related

Program that replaces multiple blanks and tabs into single blank and tab

I'm reading The C Programming Language.
I have used this program to replace multiple blanks to single blanks but I want to replace multiple blanks and tabs into single blank and tab in same time
#include <stdio.h>
int main() {
int c;
while ((c = getchar()) != EOF) {
if (c == ' ') {
putchar(c);
while ((c = getchar()) == ' ')
;
}
if (c != ' ')
putchar(c);
}
}
Your program is almost correct: there is a problem if the file ends with a space as the inner loop while ((c = getchar()) == ' '); will stop and the end of file leaving c with the value EOF, which will be output as the byte 0xFF (if EOF is defined as -1, the most common value).
You should check for this possibility:
#include <stdio.h>
int main() {
int c;
while ((c = getchar()) != EOF) {
if (c == ' ') {
putchar(c);
while ((c = getchar()) == ' ')
continue;
if (c != EOF)
break;
}
putchar(c);
}
return 0;
}
It is unclear what you mean by replace multiple blanks and tabs into single blank and tab.
To replace both spaces and TABs with a single space, you just need to test both byte values:
#include <stdio.h>
int main() {
int c;
while ((c = getchar()) != EOF) {
if (c == ' ' || c == '\t') {
putchar(' ');
while ((c = getchar()) == ' ' || c == '\t')
continue;
if (c != EOF)
break;
}
putchar(c);
}
return 0;
}
Conversely, if you mean to replace multiple spaces with a single space and multiple TABs with a single TAB, a different approach can be used:
#include <stdio.h>
int main() {
int c, last = EOF;
while ((c = getchar()) != EOF) {
if (c == ' ' || c == '\t') {
if (c == last)
continue;
}
putchar(c);
last = c;
}
return 0;
}
This approach can be used for the original problem and produces simpler code:
#include <stdio.h>
int main() {
int c, last = EOF;
while ((c = getchar()) != EOF) {
if (c != ' ' || c != last) {
putchar(c);
last = c;
}
}
return 0;
}

The use of strlen on calculating the size of a string

I need to calculate the size of a string in order to apply a function (the function applied is going to depend on the size of valor.)
However, as you can see in this example, I am having some trouble using strlen in the string (in the example you can see I inserted 2 'valor' and the given strlen was 6).
Here is the code, and next to it an image of the process returned.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
char valor[5];
char naipe[5];
int c;
int i = 0;
do {
c = getchar();
if (((c > '0') && (c < '9')) || (c == 'K') || (c == 'Q') || (c == 'J') ||
(c == 'A') || (c == 'T')) {
valor[i] = c;
continue;
}
if ((c > 'A') && (c < 'Z')) {
naipe[i] = c;
i++;
}
} while (c != '\n');
printf("%ld", strlen(valor));
return 0;
}
you have two arrays and you should use two counters for them ,otherwise you would probably skip some elements of each arrays.
also you should terminate char valor[5] and char naipe[5] with '\0'.
int main() {
char valor[5];
char naipe[5];
int c;
int i = 0,j=0;
do {
c = getchar();
if (((c > '0') && (c < '9')) || (c == 'K') || (c == 'Q') || (c == 'J') ||
(c == 'A') || (c == 'T')) {
valor[j] = c;
j++;
continue;
}
if ((c > 'A') && (c < 'Z')) {
naipe[i] = c;
i++;
}
} while (c != '\n');
valor[j] = '\0';//terminate first then print.
printf("%ld", strlen(valor));
naipe[i] = '\0';
return 0;
}

Not being able to get backspace character (\b) in the output

#include <stdio.h>
main()
{
int c;
while ((c = getchar()) != EOF) {
if (c == '\t') {
putchar('\\');
putchar('t');
}
if (c == '\b') {
putchar('\\');
putchar('b');
}
if (c == '\\') {
putchar('\\');
putchar('\\');
}
if (c != '\t')
if (c != '\b')
if (c != '\t')
putchar(c);
}
}
My question is - why can't i see the \b output? I'm currently learning K&R C and using Windows 10. I can't get a \b symbol in the Windows command line, while on Ubuntu it works pretty much ok. I've tried CTRL + H, but still no \b. Is there a way to fix this?

Counting Tab, Blank and Newlines in C [duplicate]

This question already has answers here:
How do curly braces and scope wоrk in C?
(4 answers)
What does a 'for' loop without curly braces do?
(4 answers)
Closed 5 years ago.
The code won't work. The counting results of b(blank) and t(tab) are both 0. I think there maybe the issue with my condition set up. Can anyone help?
main()
{
int c, b, t, nl;
nl = 0;
b = 0;
t = 0;
while ((c = getchar()) != EOF)
if (c == '\n')
++nl;
if (c == ' ')
++b;
if (c == ' ')
++t;
printf("%d\t%d\t%d\n", nl, b, t);
}
The code as posted by you is equivalent to:
main()
{
int c, b, t, nl;
nl = 0;
b = 0;
t = 0;
while ((c = getchar()) != EOF) //your code is equivalent to this
{
if (c == '\n')
++nl;
} //the following if conditions fall outside the loop
if (c == ' ')
++b;
if (c == '\t')//tab is represented by \t not by ' '
++t;
printf("%d\t%d\t%d\n", nl, b, t);
}
You need to add braces around your while loop i.e.
int main(void)
{
int c, b, t, nl;
nl = 0;
b = 0;
t = 0;
while ((c = getchar()) != EOF){
if (c == '\n')
++nl;
if (c == ' ')
++b;
if (c == '\t')
++t;
}
printf("%d\t%d\t%d\n", nl, b, t);
return 0;
}
Another important thing: main() is not standard C
how does int main() and void main() work
Two spaces is not char, it is string.
Try this:
if(c == ' ')
b++;
if(c == '\t')
t++;
if(c == '\n')
nl++;

How do I replace more than one blank in c programming with one blank?

I am new to programming, and I have decided to start with c. I am using the book of K & R, and there is this exercise, which asks to write a program that copies input to output , replacing one or more blanks with a single blank. However when I wrote my program (and I am sure it's not correct but that's okay, since I am here to learn) I was wondering what I am doing wrong. Also a note: when I type my name with 3 blanks it's reduced to two, but when using two or one blank(s) nothing happens. Code posted below
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int c; // getchar value
int blanks = 0; // counting the amount of blanks. If more than one then replace with blanks_2
char blanks_2 = ' '; //character value for replacement in case blanks is more than one
printf("Enter your name please\n");
while((c = getchar()) != EOF){
if(c == ' '){
++blanks;
if (blanks >= 1){
putchar(blankos); }
}
if(c >= 'a' && c <= 'z'){
putchar(c);
}
if (c >= 'A' && c <= 'Z'){
putchar(c);
}
}
return 0;
}
You do not need to count the exact number of blanks. Once you find a blank "raise a flag" that blank is found. When you revisit a non-blank character print a blank and turn the flag back to 0. Moreover, insert "continue" statements in your code to avoid unecessary checks:
int main(void)
{
int c; // getchar value
int blankfound = 0;
printf("Enter your name please\n");
while((c = getchar()) != EOF){
if(c == ' '){
blankfound = 1;
continue;
}
if(c >= 'a' && c <= 'z'){
if (blankfound == 1)
{
putchar(' ');
blankfound = 0;
}
putchar(c);
continue;
}
if (c >= 'A' && c <= 'Z'){
if (blankfound == 1)
{
putchar(' ');
blankfound = 0;
}
putchar(c);
continue;
}
}
return 0;
}
I guess you are trying to write a program that get something like this as input:
John David Doe
and display this as output:
John David Doe
by removing all extra spaces. This should work:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int c; // getchar value
int blanks = 0; // counting the amount of blanks. If more than one then replace with blanks_2
printf("Enter your name please\n");
while((c = getchar()) != EOF)
{
if(c == ' ')
{
// count blanks
++blanks;
if (blanks==1)
putchar(c); // display only the 1st blank
}
if(isalpha(c))
{
putchar(c);
blanks=0; // reset blanks counter as c is an alpha character
}
}
return 0;
}
Many of these learner code assignments work on the idea of function based on a previous character.
Consider the following layout
int previous = something();
while ((c = getchar()) != EOF) {
do_stuff(previous, c);
previous = c;
}
For OP, that would be: If the character is not a space or the previous character was not a space, print it.
printf("Enter your name please\n");
int previous = 0;
int c;
while((c = getchar()) != EOF) {
if ((c != ' ') || (previous != ' ')) {
putchar(' ');
}
previous = c;
}
Simplifying the algorithm helps one see flaws like below. blanks is not reset when a letter appears. It prints when 1 or more spaces encountered.
if(c == ' '){
++blanks;
if (blanks >= 1){
putchar(blankos); }
}
if(c >= 'a' && c <= 'z'){
putchar(c);
}
if (c >= 'A' && c <= 'Z'){
putchar(c);
}
Reference to previous chapters (Used only 'while' and 'if'), my code look like this.
#include <stdio.h>
main()
{
int c;
while ((c = getchar()) != EOF) {
if (c == ' ') {
putchar(c);
while ((c = getchar()) == ' ')
;
}
putchar(c);
}
}

Resources