a c programming question - c

all. I am not sure whether it is appropriate to ask such a 'simple' question here, but actually it's hard for me :[ , and here is the question and a bit of c code:
main()
{
int c, i;
for (i = 0; (c = getchar()) != EOF && c != '\n'; ++i)
printf("%d", i);
if (c == '\n')
printf("%d", i);
}
After executing this program, when I input, say, "abc\n", the program will return:
0
1
2
3
I wondered why the result is not
0
1
2
since when c == '\n', there are no statement that increments i by 1. This is what I thought, I must be wrong, would you tell me where I was wrong? Thanks!

The sequence of operations in the for loop are:
i = 0
(c = getchar()) != EOF && c != '\n' // c is set to 'a'
printf("%d", i) // displays 0
++i // i == 1
(c = getchar()) != EOF && c != '\n' // c is set to 'b'
printf("%d", i) // displays 1
++i // i == 2
(c = getchar()) != EOF && c != '\n' // c is set to 'c'
printf("%d", i) // displays 2
++i // i == 3
(c = getchar()) != EOF && c != '\n' // c is set to '\n'
// the loop exits
So the printf() that's after the for loop prints the most recent value for i, which is 3.

The ++i gets executed after the c == '\n' case.
Perhaps this code would help clarify?
int i;
for (i = 0; i <= 3; ++i)
printf("%d\n", i);
At the end of the loop, i will be 4, because of that final increment.

The main problem is with pre increment of index variable i. In stead of pre increment, use post increment i.e. i++ inside the for loop.The reason behind that is due to pre increment. When the condition inside the loop halts, the value stored in i is already 4 when you use pre increment.
main()
{
int c, i;
for (i = 0; (c = getchar()) != EOF && c != '\n'; i++)
printf("%d", i);
if (c == '\n')
printf("%d", i);
}

Related

if/else not receiving value at array in C [duplicate]

#include<stdio.h>
#include<ctype.h>
int peekchar() {
int c;
c = getchar();
if (c != EOF) {
ungetc(c, stdin);
}
return c;
}
int readNumber(void) {
int c;
int accumulator = 0;
while ((c = peekchar() != EOF) && isdigit(c)) {
c = getchar();
accumulator *= 10;
accumulator += c - '0';
}
return accumulator;
}
int main() {
int result = readNumber();
printf("%d\n", result);
return 0;
}
I am trying to read an integer written in decimal notation from stdin until the first non-digit. But its not giving the correct result:
M1508444:CProg sb054043$ gcc -g3 readNumber.c -o readNumber
M1508444:CProg sb054043$ ./readNumber
123
0
Can someone please help me identify the problem?
The issue is with operator precedence. c = peekchar() != EOF is grouped as c = (peekchar() != EOF), and so c is either 0 or 1, which accounts for the result.
Fix with (c = peekchar()) != EOF.
Or, given that isdigit is defined to be 0 for EOF, your loop conditional can be simplified to
while (isdigit(c = peekchar())){
Hi you need to modify your while loop like below:-
while ( (c = peekchar()) != EOF && isdigit(c)) {
c = getchar();
accumulator *= 10;
accumulator += c - '0';
}
First of all you need to read the value and store it in variable c and that you can achieve by doing (c = peekchar()). Once the value stored in c now your while loop will first check whether it is EOF if not then only it will check whether it is a digit or not.

Why having getchar() assigned to a variable in a while loop condition leads to output of 0?

So currently I'm learning C from the C programming language 2nd edition book and it says that:
while (c = getchar() != EOF) {
}
is identical to:
while (c != EOF) {
c = getchar();
}
However, when I run the code I just had written:
#include <stdio.h>
int main() {
char c;
int times;
while (c = getchar() != EOF) {
if (c == 'a') {
++times;
}
}
printf("%d\n", times);
}
The value of times it outputs is 0 instead of actual value of times I typed in 'a' character.
Now in this code, it works fine:
#include <stdio.h>
int main() {
char c;
int times;
while (c != EOF) {
c = getchar();
if (c == 'a') {
++times;
}
}
printf("%d\n",times);
}
and if I type a 3 times, the value it outputs is 3.
Precedence!
c = getchar() != EOF
means
c = ( getchar() != EOF ) // Assigns `0` or `1` to `c`.
but you want
( c = getchar() ) != EOF
Also note that c needs to be an int.
This means you could use
for (int c; ( c = getchar() ) != EOF; ) {
...
}
but I prefer
while (1) {
int c = getchar();
if (c == EOF)
break;
...
}
Operator precedence.
!= operator is higher in precedence than =, so your expression is equivalent to:
while (c = (getchar() != EOF))
use a parenthesis around c=getchar() and it will work.

What does this condition (s[i] && s[i] != c) means?

#include <stdio.h>
char s[] = "`1234567890-=QWERTYUIOP[]\\ASDFGHJKL;'ZXCVBNM,./";
int main ()
{
int i, c;
while ((c = getchar()) != EOF) {
for (i = 1; s[i] && s[i] != c; i++);
if (s[i]) putchar(s[i-1]);
else putchar(c);
/* code */
}
return 0;
}
Whats does the condition s[i] && s[i] != c; inside the for loop mean?
I haven't seen it before.
Thanks!
First of all the variable s is a null terminated C-string, which is an array of chararcters with the last character being '\0'. You access that array with the index i in your code.
With that for loop you loop through the s string until a null terminator '\0' or the char c is found.
The null terminator '\0' is 0 decimal which means false in boolean logic because everthing else than 0 is true.
If you write for example:
char a = 'A'; /* same as char a = 65; */
if (a) { ... }; /* same as if (a != 0) */
that means: if a is true which is: if a is not false and better: if a is not equal to 0. This statement will evaluate to true because 'A' is 65 decimal (ASCII code) which is not equal to 0.
The for loop you've asked for can be rewritten as:
for (i = 1; s[i] != '\0' && s[i] != c; i++);
I would recommend to use explicit statements like s[i] != '\0' because it is easier to read.
s[i] in if is going to check whether an element exists on s[i] . if element exists on s[i] then it's truthy if not then it's falsy .
c is being intialized with user input in while loop
c = getchar()
s[i] != c // it means that my inputted value can not be equal to s[i].

Function to read line from standard input in C not working as expected

This function is supposed to get a line from the terminal. But it doesn't! I have gone over the code multiple times, but I haven't been able to pinpoint the problem! Please help! It doesn't seem that the code is entering the while block.
int getline(char line[]) {
int i = 0 ;
int c ;
while( ((c=getchar()) != EOF) && (c =! '\n') ) {
line[i++] = c ;
}
line[i] = '\0' ;
return i ;
}
Well this is incorrect
while( ((c=getchar()) != EOF) && (c =! '\n') )
it should be
while( ((c=getchar()) != EOF) && (c != '\n') )
Do you notice the difference? != is comparison (which is correct), and =! is completely different (which means negating '\n' and assign it to c) - which was wrong. So, attentions to the details please :)

Kernighan and Ritchie Exercise 2-2 Debugging?

I am working through K&R (2nd edition) for my own edification and encountered the following exercise (exercise 2-2 p42):
Write a loop equivalent to the following without using && or ||:
for (i=0; i<lim-1 && (c=getchar()) != '\n' && c != EOF; ++i)
s[i] = c;
This was my solution:
#include <stdio.h>
/* write a loop equivalent to the following without using && or ||
for (i=0; i<lim-1 && (c=getchar()) != '\n' && c != EOF; ++i)
s[i] = c;
*/
int main()
{
int counter = 0, lim = 1000;
int s[lim], c;
while(counter < lim-1)
{
while((c = getchar()) != '\n')
{
while(c != EOF)
{
s[counter] = c;
}
}
counter++;
}
return 0;
}
I was expecting the indented loops and therefore the entire program to exit normally once it encountered a newline character ('\n') or an EOF character (Ctrl-d on my Linux machine), but to my surprise it happily soldiers on. I tried to debug it using gdb but still could not figure it out.
What am I not seeing?
Addendum: I tried to reverse the sequence of tests the while loops perform and added an if statement to break out of the outer loop if c == '\n' but am still not seeing it! I am also having difficulty trying to run GDB entering text into the command line and simultaneously printing the value of c, even when I tried to link gdb to the pid of a running copy of the executable. I realize that there are probably other ways to solve this exercise, e.g. setting an OK_TO_EXECUTE flag or variable that is true only if all three conditions are met, but I am bothered by the fact that I seem unable to find the bug in a seemingly simple program. This is precisely why I am returning to K&R to go through the book more thoroughly and to solve the exercises properly.
Redone code (still buggy!!!):
#include <stdio.h>
/* write a loop equivalent to the following without using && or ||
for (i=0; i<lim-1 && (c=getchar()) != '\n' && c != EOF; ++i)
s[i] = c;
*/
int main()
{
int counter = 0, lim = 1000;
int s[lim], c;
while((c = getchar()) != EOF)
{
if ( c == '\n')
break;
while(c != '\n')
{
while(counter < lim-1)
{
s[counter] = c;
counter++;
}
}
}
return 0;
}
SOLVED! - I think! I think I have finally figured it out. The inner loops as written in my redone solution will still loop endlessly or at lease till lim is reached. I added break
statements and think I am on my way to a solution.
I am still wrestling with how to run gdb on this problem though; enter the command line entries AND print the value of c. Linking gdb to the pid of the executable still did not work as expected. I even posted a separate question regarding gdb.
but to my surprise it happily soldiers on
You have three nested loops. A newline would terminate one of the inner loops, while the outermost loop would happily carry on (until you've hit Enter lim times).
I can give you a hint: you probably shouldn't be using nested loops for this.
You have added loops that didn't exist in the original ... that's conceptually and logically wrong. The most obvious solution uses break:
for (i = 0; i < lim-1; ++i)
{
c = getchar();
if (c == '\n')
break;
if (c == EOF)
break;
s[i] = c;
}
Or if you're pretending that C doesn't have break, you can do something like this (this is not exactly equivalent because i doesn't have the same value if '\n' or EOF is encountered):
for (i = 0; i < lim-1;)
{
c = getchar();
if (c == '\n')
i = lim-1;
else if (c == EOF)
i = lim-1;
else
s[i++] = c;
}
Or you can use the Pascal approach:
#include <stdbool.h>
...
i = 0;
bool more = i < lim-1;
while (more)
{
c = getchar();
if (c == '\n')
more = false;
else if (c == EOF)
more = false;
else
{
s[i++] = c;
more = i < lim-1;
}
}
With goto
i=0;
loop:
if( i >= lim - 1) goto end;
c = getchar();
if(c == '\n') goto end;
if(c == EOF) goto end;
s[i++] = c;
goto loop;
end:
Without break, goto and with just one for, still without && and ||.
for (i=0; i < lim - 1 ? ((c=getchar()) == '\n' | c == EOF) == 0 : 0; ++i)
s[i] = c;
Update
As noted by #Jim it's way better to set order of execution explicitly by using internal ?:
for (i=0; i >= lim - 1 ? 0 : (c=getchar()) == '\n' ? 0 : c != EOF; ++i)
s[i] = c;

Resources