I'm trying to read in an integer using getchar(). This is the code I'm using:
while (thisChar = getchar() != '\n') {
n = n * 10 + thisChar - '0';
}
int n is initialized to zero and thisChar is declared as an int
For single digit input, n is returning as -47 which means the character value for start of heading is being read in first. Is there something incorrect about the way I am assigning thisChar in the while expression?
It's missing parentheses:
int thisChar;
while ((thisChar = getchar()) != '\n') {
n = n * 10 + thisChar - '0';
}
Without these additional parentheses, you always assign to thisChar the value of the comparison getchar() != '\n', i.e. always 1 or 0 ...
Note that you should also handle EOF:
int thisChar = getchar();
while (thisChar != EOF && thisChar != '\n') {
n = n * 10 + thisChar - '0';
thisChar = getchar();
}
!= have higher precedence than that of = operator. Therefore, the expression
while(thisChar = getchar() != '\n') {...}
will be parsed as
while(thisChar = (getchar() != '\n')) {...}
and the result of the comparison getchar() != '\n') will be assigned to thisChar.
You need to put the sub-expression thisChar = getchar() inside a bracket
while((thisChar = getchar()) != '\n') {...}
Related
I need to read a PPM file but I'm limited to only using getchar() but I'm running into trouble ignoring whitespaces.
I'm using num=num*10+(ch-48); to read the height and width but don't know how to read them all at once while ignoring spaces and '\n' or comments.
I use this to read the magic number:
int magic;
while(magic==0){
if (getchar()=='P') //MAGIC NUMBER
magic=getchar()-48;
}
printf("%d\\n",magic);
i used this function to read the height and width which works only when the data in the header is seperated only by '\n'
int getinteger(int base)
{ char ch;
int val = 0;
while ((ch = getchar()) != '\\n' && (ch = getchar()) != '\\t' && (ch = getchar()) != ' ')
if (ch \>= '0' && ch \<= '0'+base-1)
val = base\*val + (ch-'0');
else
return ERROR;
return val;
}
this is the part in main()
height=getinteger(10);
while(height==-1){
height=getinteger(10);
}
Comparing "magic" with 0 is undefined behaviour since it's not initialized yet (so it's basically just a chunk of memory):
int magic; // WARNING: We don't know exact value, may be not 0
while(magic==0){
if (getchar()=='P') //MAGIC NUMBER
magic=getchar()-48;
}
Consider initializing variable before comparing:
int magic = 0; // We know that magic will be defined as 0
while (magic == 0) {
if (getchar() == 'P') // MAGIC NUMBER
magic = getchar() - 48;
}
In this function:
int getinteger(int base)
{ char ch;
int val = 0;
while ((ch = getchar()) != '\\n' && (ch = getchar()) != '\\t' && (ch = getchar()) != ' ')
if (ch \>= '0' && ch \<= '0'+base-1)
val = base\*val + (ch-'0');
else
return ERROR;
return val;
}
(I'm assuming that ERROR = -1, is that correct?) In your condition getchar() will work 3 times, not 1 (since it calls getchar() for putting in ch every check). Rewrite it to call only once for saving in variable ch. Another problem occurs when first symbol will be whitespace, not digit. In this case val will remains 0 (since while loop will be skipped), so returned value will also be '0'. To avoid this, you can check value of val and return ERROR, when it is not changed:
int getinteger(int base) {
char ch = getchar(); // get only one char and save for later use
int val = 0; // 0 means not changed
while (ch != '\n' && ch != '\t' && ch != ' ') {
if (ch >= '0' && ch <= '0' + base - 1)
val = base * val + (ch - '0');
else
return ERROR;
ch = getchar(); // get a new char for next loop iteration and checking if it is digit
}
if (val == 0) // val was not changed
return ERROR; // loop in "main" will be continued
else
return val; // val was changed, return it
}
UPD: We can also use this fact to simplify our function a lot:
int getinteger(int base) {
char ch = getchar(); // get only one char and save for later use
int val = 0; // 0" means not changed
while (ch >= '0' && ch <= '0' + base - 1) { // if "ch" is not a number, this loop will be skipped
val = base * val + (ch - '0');
ch = getchar(); // get a new char for next loop iteration and checking if it is digit
}
if (val == 0) // val was not changed (ch was not a number)
return ERROR; // loop in "main" will be continued
else
return val; // val was changed, return it
}
And last but not least, remove extra '' before symbols (\\n -> \n, \>= -> >= etc.) if they present in your code.
Combining everything above results in something like this:
#include <stdio.h>
#define ERROR -1
int getinteger(int base) {
char ch = getchar(); // get only one char and save for later use
int val = 0; // 0 means not changed
while (ch >= '0' && ch <= '0' + base - 1) { // if "ch" is not a number, this loop will be skipped
val = base * val + (ch - '0');
ch = getchar(); // get a new char for next loop iteration and checking if it is digit
}
if (val == 0) // val was not changed (ch was not a number)
return ERROR; // loop in "main" will be continued
else
return val; // val was changed, return it
}
int main() {
// dunno what's before
int magic = 0; // We know that magic will be defined as 0
while (magic == 0) {
if (getchar() == 'P') // MAGIC NUMBER
magic = getchar() - 48;
}
printf("magic = %d\n", magic);
int height = getinteger(10);
while (height == -1)
height = getinteger(10);
printf("height = %d\n", height);
// dunno what's after
}
Result:
$ echo " \n P3 #blabla \n 34 \t " | ./a.out
magic = 3
height = 34
I need to write a program that reads from the input a sentence terminated by a new line. The program should write an encryption of the sentence in a way that the letter 'a' is swapped with 'z', 'b' with 'y' and so on. I am not supposed to use arrays, that is why I can't find a solution for this problem.
This is my code:
#include<stdio.h>
int main() {
char alphabet, temp;
while( scanf("%c", &alphabet) != '\n') {
for(char i ='a', j='z'; i <= 'z', j>='a'; i++, j--) {
if(alphabet == i) {
temp = j;
}
}
printf("%c", temp);
}
return 0;
}
When I input: abc as an output I get zyxxxxxxxxxxxxxxxxxxxxxxxxx(an infinite number of x).
So to sum up:
Input:abc. Output: zyxxxxx(infinite number of x).
You messed up the return value of scanf:
while( scanf("%c", &alphabet) != '\n'){
You want to stop the loop when the entered character (in alphabet) is a line break.
But you test the return value of scanf which will never be '\n' as it returns the number of converted fields.
You could try like this:
while( scanf("%c", &alphabet) == 1 && alphabet != '\n'){
Compile your code with warnings enabled (e.g. Wall flag)! This:
for(char i ='a', j='z'; i <= 'z', j>='a'; i++, j--)
should give:
warning: left-hand operand of comma expression has no effect [-Wunused-value]
You need to use the logical AND operator && and not a comma between the two comparissons.
Moreover, use getchar() instead, like this:
#include<stdio.h>
int main() {
char temp;
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
for(char i ='a', j='z'; i <= 'z'&& j>='a'; i++, j--){
if(ch == i){
temp = j;
}
}
if(ch <= 'z'&& ch >= 'a') // do not print if 'ch' is a digit for example
printf("%c", temp);
}
return 0;
}
Output:
zyx
If you have to use scanf(), then try reading into alphabet, check the return value of scanf, and compare to newline, like this:
while(scanf("%c", &alphabet) != 0 && alphabet != '\n')
I'm new to programming and learning C through a book.
The author of the book explains about logical operators (AND, NOT and OR) by giving the following example which counts the number of characters except the double or single quotes and period character.
I couldn't understand how it counts the number of characters except the quotes and period character. I understand that with the AND operator both conditions should be true.
#include <stdio.h>
#define PERIOD '.'
int main(void)
{
char ch;
int charcount = 0;
while ((ch = getchar()) != PERIOD)
{
if (ch != '"' && ch != '\'')
charcount++;
}
printf("There are %d non-quote characters.\n", charcount);
return 0;
}
I will try to explain you the main part of the code :
while ((ch = getchar()) != PERIOD)
{
Here, it will check every character contained in your text, as long as the character differ from PERIOD, which is a dot, so it simply check all of the characters in the sentence.
if (ch != '"' && ch != '\'')
charcount++;
}
Here, it adds 1 to the charcount if the condition is true. For the if to return true, both ch != '"' and ch != '\'' must be true ! The && operator is a logical AND, and for an AND to return true (1), both conditions must be equal to 1. So if the character is equal to " or ', the AND will return 0, and so we won't add 1 to the charcount.
This condition if (ch != '"' && ch != '\''), is checking if the entered character is "or ' if not then it increments the count of characters otherwise not. If user enterd d or #, it will satisfy the condition because ASCII value of # is not equal to " or ', and the count will get incremented.
Well, for each char returned by getchar() and stored in ch (from an input stream, like a keyboard or a file) it will test if it's not a double quote (ch != '"') and if it's not a quote (ch != '\'')
\ is an escape character, which means '\'' is the char '
If it's neither of them, then it will increments the counter (charcount++;).
And this will go on as long as getchar() doesn't return a period ((ch = getchar()) != PERIOD)(if it does, the PERIOD won't be counted as the code will step out the will loop immediately).
You can skip using continue:
#include<stdio.h>
#define PERIOD '.'
int main(void)
{
char ch;
int charcount = 0;
while ((ch = getchar()) != PERIOD)
{
if (ch != '"' && ch != '\''){
continue;
}
charcount++;
}
printf("There are %d non-quote characters.\n", charcount);
return 0;
}
Output:
./program
Michi"""LoL'''Another'"LoL.
There are 8 non-quote characters.
Here is the function definition of get_line which:-
skip whitespaces in the begining.
stop at first white space.
stop at first newline character and place it in the array.
leave behind character if it does not have space available.
int get_line (char* ch, int n)
{
if ( n <= 0)
return 0;
char c;
while ( isspace(c = getchar()));
int i = 0;
do {
ch[i++] = c;
if ( i == n)
break;
}while ( ! isspace(c = getchar()));
if ( c == '\n')
ch[i++] = '\n';
ch[i] = '\0';
return i;
}
int main()
{
char array[5];
get_line(array, 4);
printf("%s", array);
char c;
while ( (c = getchar()) != '\n'){
printf("\n%c", c);
}
return 0;
}
But when i enter more characters then the size and try to print the remaining character in main using the last while loop, it prints weird characters and not printing the remaining characters in the stream as required by the fourth specification of the function. Please tell me why this is happening?
It looks like you ran afoul of operator precedence.
In this statement:
while ( c = getchar() != '\n'){
The comparison operator != has higher precedence than the assignment operator =. So getchar() != '\n' is evaluated first and will be either 1 or 0 since it is a boolean expression.
Assuming the next character is not a newline, the value will be 1. Then c = 1 is evaluated and the loop continues by printing the value 1 as a char. When a newline is found, getchar() != '\n' evaluates to 0, then c = 0 is evaluated and the loop exits.
You need to add parenthesis here to get the intended order of operations:
while ( (c = getchar()) != '\n'){
WhozCraig pointed out that your problem is the operator precedence. This is what happens:
while ( c = getchar() != '\n'){
printf("\n%c", c);
}
In the condition expression of your while statement, first the experssion getchar() != '\n' is evaluated. Then the result of this is assigned to c. The expression yields the result of the comparission of the call to getchar(), which retrieves the next character, with the constant character value '\n'.
Depending on how the comparisson operator != is implemented, you can get weird characters. Note that Boolean 'true' in C is defined as non-zero and Boolean 'false' as zero. For example, it would be perfectly legal for the compiler to subtract the byte value of \n from the 'getchar() result and test for non-zero. In assembler this would look something like:
call getchar
sub ax, 0x0d ' getchar result in ax; subtract \n from it
mov c, ax ' move result of subtraction to variable c
jz end_loop ' end loop if zero (= equal)
After succesfully running an entabulator, my detabulator won't pick up on a character comparison that should exit a while loop. After trying "0(tab)8(enter)(ctrl+D)" as input the tab is written correctly as spaces, but after rp is incremented to point to the 8, the while loop that should read the 8 won't exit and I get a seg fault. Here's the code:
#include <string.h>
#include <stdio.h>
#define MAXLINE 100
char doc[9001];
main(int argc, char *argv[])
{
int max = 0;
char *rp = doc;
char *wp = rp;
char *tf = wp;
char *lp = doc;
while ((*(rp++) = getchar()) != EOF);
*--rp = '\0';
rp = doc;
j = 0;
while ( (*rp != '\0') && (argc == 1)) {
if (*rp == '\n') {
lp = rp + 1;
*wp++ = *rp++;
}
while( (*rp != '\t') && (*rp != '\0') && (*rp != '\n') ) { /*this loops after a tab*/
*wp++ = *rp++;
}
if (*rp == '\t') {
rp++;
tf = lp + ((((wp - lp) / 8) + 1) * 8);
while ((tf - wp) != 0)
*wp++ = 's';
}
}
if (*rp == '\0')
*wp = '\0';
printf("%s\n", doc);
}
There are some as yet unexplored problems with the initial input loop.
You should never risk overflowing a buffer, even if you allocate 9001 bytes for it. That's how viruses and things break into programs. Also, you have a problem because you are comparing a character with EOF. Unfortunately, getchar() returns an int: it has to because it returns any valid character value as a positive value, and EOF as a negative value (usually -1, but nothing guarantees that value).
So, you might write that loop more safely, and clearly, as:
char *end = doc + sizeof(doc) - 1;
int c;
while (rp < end && (c = getchar()) != EOF)
*rp++ = c;
*rp = '\0';
With your loop as written, one of two undesirable things happens:
if char is an unsigned type, then you will never detect EOF.
if char is a signed type, then you will detect EOF when you read a valid character (often ΓΏ, y-umlaut, LATIN SMALL LETTER Y WITH DIAERESIS, U+00FF).
Neither is good. The code above avoids both problems without needing to know whether plain char is signed or unsigned.
Conventionally, if you have an empty loop body, you emphasize this by placing the semicolon on a line on its own. Many an infinite loop has been caused by a stray semicolon after a while condition; by placing the semicolon on the next line, you emphasize that it is intentional, not accidental.
while ((*(rp++) = getchar()) != EOF);
while ((*(rp++) = getchar()) != EOF)
;
What I feel is, the below loop is going into infinite loop.
while( (*rp != '\t') && (*rp != '\0') && (*rp != '\n') ) { /*this loops after a tab*/
*wp++ = *rp++;
This is because, you are checking for rp!= '\t' and so on, but here
if (*rp == '\t')
{
rp++;
tf = lp + ((((wp - lp) / 8) + 1) * 8);
while ((tf - wp) != 0)
*wp++ = 's';
}
you are filling the doc array with char 's' and which is over writing '\t' also, so the above loop is going to infinite.