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)
Related
My friend asked me what is (char)getchar() which he found in some online code and I googled and found 0 results of it being used, I thought the regular usage is just ch = getchar(). This is the code he found, Can anyone explain what is this function?
else if (input == 2)
{
if (notes_counter != LIST_SIZE)
{
printf("Enter header: ");
getchar();
char c = (char)getchar();
int tmp_count = 0;
while (c != '\n' && tmp_count < HEADER)
{
note[notes_counter].header[tmp_count++] = c;
c = (char)getchar();
}
note[notes_counter].header[tmp_count] = '\0';
printf("Enter content: ");
c = (char)getchar();
tmp_count = 0;
while (c != '\n' && tmp_count < CONTENT)
{
note[notes_counter].content[tmp_count++] = c;
c = (char)getchar();
}
note[notes_counter].content[tmp_count] = '\0';
printf("\n");
notes_counter++;
}
}
(char)getchar() is a mistake. Never use it.
getchar returns an int that is either an unsigned char value of a character that was read or is the value of EOF, which is negative. If you convert it to char, you lose the distinction between EOF and some character that maps to the same char value.
The result of getchar should always be assigned to an int object, not a char object, so that these values are preserved, and the result should be tested to see if it is EOF before the program assumes a character has been read. Since the program uses c to store the result of getchar, c should be declared as int c, not char c.
It is possible a compiler issued a warning for c = getchar(); because that assignment implicitly converts an int to a char, which can lose information as mentioned above. (This warning is not always issued by a compiler; it may depend on warning switches used.) The correct solution for that warning is to change c to an int, not to insert a cast to char.
About the conversion: The C standard allows char to be either signed or unsigned. If it is unsigned, then (char) getchar() will convert an EOF returned by getchar() to some non-negative value, which will be the same value as one of the character values. If it is signed, then (char) getchar() will convert some of the unsigned char character values to char in an implementation-defined way, and some of those conversions may produce the same value as EOF.
The code is a typical example of incorrect usage of the getchar() function.
getchar(), and more generally getc(fp) and fgetc(fp) return a byte from the stream as a positive value between 0 and UCHAR_MAX or the special negative value EOF upon error or end of file.
Storing this value into a variable of type char loses information. It makes testing for EOF
unreliable if type char is signed: if EOF has the value (-1) it cannot be distinguished from a valid byte value 255, which most likely gets converted to -1 when stored to a char variable on CPUs with 8-bit bytes
impossible on architectures where type char is unsigned by default, on which all char values are different from EOF.
In this program, the variables receiving the getchar() return value should have type int.
Note also that EOF is not tested in the code fragment, causing invalid input strings such as long sequences of ÿÿÿÿÿÿÿÿ at end of file.
Here is a modified version:
else if (input == 2)
{
if (notes_counter != LIST_SIZE)
{
int c;
// consume the rest of the input line left pending by `scanf()`
// this should be performed earlier in the function
while ((c = getchar()) != EOF && c != '\n')
continue;
printf("Enter header: ");
int tmp_count = 0;
while ((c = getchar()) != EOF && c != '\n') {
if (tmp_count + 1 < HEADER)
note[notes_counter].header[tmp_count++] = c;
}
note[notes_counter].header[tmp_count] = '\0';
printf("Enter content: ");
tmp_count = 0;
while ((c = getchar()) != EOF && c != '\n')
if (tmp_count + 1 < CONTENT)
note[notes_counter].content[tmp_count++] = c;
}
note[notes_counter].content[tmp_count] = '\0';
printf("\n");
notes_counter++;
}
}
I'm a novice programmer who's self-studying C through K&R. I don't understand the design of their function getint(), which converts a string of digits into the integer it represents. I'll ask my question then post the code below.
If getch() returns a non-digit character that's not a '-' or '+', it pushes this non-digit character back onto the input with ungetch(), and returns 0. So, if getint() is called again, getch() will just return that same non-digit character that was pushed back, so ungetch() will push it back again, etc. The way I understand it (which could be wrong), the function breaks completely if it's passed any non-digit character.
The exercise doesn't have you fix this. It asks to fix the fact that a '-' or '+' followed by a non-digit is a valid representation of 0.
What exactly am I missing here? Did they design getint() to make an infinite loop if the input is anything other than 0-9? Why?
Here's their code for getint() [edit] with main calling getint():
int getint(int *);
int main()
{
int n, array[BUFSIZE];
for (n = 0; n < BUFSIZE && getint(&array[n]) != EOF; n++)
;
return 0;
}
int getch(void);
void ungetch(int);
int getint(int *pn)
{
int c, sign;
while (isspace(c = getch())
;
if (!isdigit(c) && c != EOF && c != '+' && c != '-') {
ungetch(c); //this is what i don't understand
return 0;
}
sign = (c == '-') ? -1 : 1;
if (c == '-' || c == '+')
c = getch();
for (*pn = 0; isdigit(c); c = getch())
*pn = 10 * *pn + (c - '0');
*pn *= sign;
if (c != EOF)
ungetch(c);
return c;
}
int buf[BUFSIZE];
int bufp = 0;
int getch(void)
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c)
{
if (bufp >= BUFSIZE)
printf("ungetch: can't push character\n");
else
buf[bufp++] = c;
}
As it is currently written, getint() function is trying to read an integer from user input and puts it into *pn.
If user inputs a positive or negative number(with a sign or without it), *pn gets updated to that number and getint() returns some positive number (the next character after the number).
If user inputs a non valid number, *pn is not updated and getint() returns 0 (meaning it failed).
the function breaks completely if it's passed any non-digit character.
That's right. All subsequent calls to getint() will fail as the last character was passed to ungetch(). What you understand is correct.
But this is how getint() is supposed to handle garbage input. It'll simply reject it and return 0 (meaning it failed). It is not the responsibility of getint() to take care of non-integer input and prepare fresh input for next read. It is not a bug.
The only bug is that a '-' or '+' followed by a non-digit is currently being considered as a valid representation of 0. Which is left to reader as an exercise.
If user inputs EOF, *pn is not updated (multiplied by 1) and getint() returns EOF.
The reasoning is similar to scanf not consuming characters that don't match the conversion specifier - you don't want to consume something that isn't part of a valid integer, but may be part of a valid string or other type of input. getint has no way of knowing whether the input it rejects is part of an otherwise valid non-numeric input, so it has to leave the input stream the same way it found it.
I'm having trouble finding out how to set up a loop where i enter input and then
stop the input by pressing 'e' or 'E'. The input entered is integers but needs to be stopped with a character. That is where i get lost. I have seen a bunch of information about using ascii conversions but i dont know how efficient that would be. This code is broken but it is as far as i could get. Any information would be helpful.
int main(void)
{
char num;
int sub;
while (sub != 'e' || sub != 'E') {
scanf("%d", &num);
sub = #
printf("%d", num);
}
return 0;
}
Simple.
#include <stdio.h>
#include <ctype.h>
int main(void) {
char c = getchar();
int num;
while (c != 'e' || c != 'E') {
if (isdigit(c))
num = c - '0';
c = getchar();
}
return 0;
}
But you don't have to use an ascii character as a way to stop input. You can use EOF which is -1. It is Ctrl-D on UNIX systems and Ctrl-Z on Windows.
int c;
while ((c = getchar()) != EOF)
A direct way to distinguish between an input of int, 'e' and , 'E' is to read a line of user input with fgets() and then parse it.
#define LINE_SZ 80
char buf[LINE_SZ];
while (fgets(buf, sizeof buf, stdin) && buf[0] != 'e' && buf[0] != 'E') {
if (sscanf(buf, "%d", &num) != 1) {
Handle_other_non_int_input();
}
sub = #
printf("%d", num);
}
As noted in the comments, (sub != 'e' || sub != 'E') is always true. If sub can never be e and E at the same time.
Note that sub is an int and not an integer pointer (int *).
The line sub = # assigns sub with num's address.
And the value of sub is used in the control expression of the while loop before it is initialised. sub has garbage value at that point which is indeterminate. You have to initalise it with some value before using it.
Do
int num, rv;
while( 1 )
{
rv=scanf("%d", &num);
if(rv==0)
{
if( (num=getchar())=='e' || num=='E' )
{
break;
}
else
{
while(getchar()!='\n');
continue;
}
}
printf("\n%d", num);
}
A value is read into num by scanf() whose return value is stored in rv.
scanf() returns the number of successful assignments which in this case should be 1 if an integer value was read into num since %d is the format specifier.
If rv is 1, it is a number and is printed. Otherwise it could be a character which won't read by the scanf() and would remain unconsumed in the input buffer. The first byte of this data is read by the getchar() and if this is e or E, the loop is exited but otherwise the input buffer is cleared till a \n is encountered and the next iteration of the loop is done without going into the part where the printing takes place.
When i run this code it prints the dos 0 character(space) once, puts a space and prints dos 1 character(smiley face with white eyes and mouth).
int c = 0, b = 1;
printf("%c %c", c, b);
But when i run this code below the result is being printed twice. I either get 2 spaces or 2 smiley faces.
while(c != -1)
{
c = getchar() != EOF;
putchar(c);
}
Edit: My code doesnt have paranthesis so it compares every single entered character with EOF and assigns the result (0 or 1) to c and then prints c as a char. In order to prevent this, we can use paranthesis to force the program to do c = getchar() first and then compare that value with EOF.
while((c = getchar()) != EOF)
Your problem is that a '\n' character is not equal to EOF. The '\n' is being read in as a second character.
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') {...}