Printing control characters using escaped notation - c

I need help understanding what are they really asking here.
I have written part of the program already.
Do I have to print the decimal value for the newline character and the tab character?
Why I can't get 10 pair per line all the time? Sometimes I get 10 pairs and another times not.
The assignment was:
Write a program that reads input as a stream of characters until
encountering EOF. Have the program print each input character and its
ASCII decimal value.
Note that characters preceding the space character in the ASCII
sequence are nonprinting characters. Treat them specially. If the
nonprinting character is a newline or tab, print \n or \t,
respectively. Otherwise, use control-character notation. For instance,
ASCII 1 is Ctrl+A, which can be displayed as ^A. Note that the ASCII
value for A is the value for Ctrl+A plus 64. A similar relation holds
for the other nonprinting characters. Print 10 pairs per line, except
start a fresh line each time a newline character is encountered.
This is what I have written:
#include <stdio.h>
int main(void)
{
int ch;
int i=0;
printf("Please enter some characters.\n\n");
while((ch=getchar()) != EOF)
{
if((i%10) == 0)
printf("\n");
if (ch == '\n')
printf( "\n\\n ");
else if (ch == '\t')
printf("\\t %d ", ch);
else if (ch < ' ')
printf("^%c %d ", ch+64, ch);
else
printf("%c %d ",ch, ch);
i = i+1;
}
return 0;
}

What they're asking for sounds very clear; here is some pseudo-code:
if (ch == '\n') print "\n %d", ch;
else if (ch == '\t') print "\t %d", ch;
else if (ch < ' ') { print "^"; print "%c %d", ch+'A', ch; }
else print "%c %d",ch, ch;
This is exclusive of formatting needed to make it look right; your code already has some formatting.

ASCII 0-31 are non-printing characters. Their respective control-character notations can be found at the ASCII Wikipedia page in the [b] column.
You will want to print the control-character notation for these characters, with the exception of 9 and 10, for which you will print \t and \n (backslash-t and backslash-n), respectively.
Another thing about your loop
if((i%10==0) || (ch == '\n'))
printf("\n");
These should be two separate statements. Make sure to escape your backslashes with an extra backslash beforehand as printf("\\n"); will actually print "\n" (backslash-n) whereas printf("\n") will just print an actual line feed, which I'm almost certain is not what your instructor is asking for here, except after each ten entries.

Have a look at the Wikipedia pages about ASCII, the caret notation (which is similar to control notation). I don't want to post the solution here. :D

Related

Undefined behaviour of scanf() in a do-while loop

I'm currently learning C by a book "C Programming a modern approach" and encountered this code. When I tried to run it, after typing consecutive characters like 'abc' and hitting Enter (new line), nothing was printed. Please explain what is going on here.
char ch;
do {
scanf("%c" , &ch);
} while (ch != '\n');
printf("%c", ch);
You're asking the user to input a character using scanf. This is happening in a loop until the user inputs a '\n' or newline character (the same as pressing the enter key), which is when the loop will break.
Your print statement will then print the character in the variable ch, which at that point will be '\n' (since this variable just stores one character, the last one you typed).
This newline character will probably be invisible when you run your program so you may not be seeing it. You can add another print statement after the loop and if that print statement starts at a newline, you know that the '\n' was printed on the previous line.
Something like:
#include <stdio.h>
int main()
{
char ch;
do
{
scanf("%c" , &ch);
} while (ch != '\n');
printf("%c", ch);
printf("I should show up on a newline");
return 0;
}
The code you provided reads characters from the input using the scanf() function and stores them in the variable ch until a newline character (\n) is encountered. After that, the program prints the last character that was read, which is the newline character.
The reason you are not seeing any output when you enter characters followed by a newline character is because the printf() statement is only executed after the loop has finished running. So, the program is waiting for you to enter a newline character to terminate the loop and print the last character that was read.
If you want to see the characters you enter, you can add a printf() statement inside the loop, like this:
char ch;
do {
scanf("%c" , &ch);
printf("%c", ch);
} while (ch != '\n');
This will print out each character as it is read from the input, so you can see what you're typing. Happy coding :)
When I tried to run it, after typing consecutive characters like abc and hitting Enter (new line), nothing was printed.
Well with the posted code, if the loop even finishes, the last byte read by scanf("%c", &ch) and stored into ch is the newline character. Hence printf("%c", ch) outputs this newline and it seems nothing is printed but something is, the newline which is invisible on the terminal but does move the cursor to the next line.
You can make this more explicit by changing the printf call to this:
printf("last value: '%c'\n", ch);
Note however that the posted code is not a recommended way to read the contents of the input stream:
scanf("%c", &ch) may fail to read a byte if the stream is at end of file. Failure to test this condition leads to undefined behavior (ch is unmodified, hence stays uninitialized if the input stream is an empty file) or to an infinite loop as ch may never receive a newline.
this code is a typical example of a do / while with a classic bug. It would be much better to write the code using getchar() and a while loop.
Here is a modified version:
#include <stdio.h>
int main(void) {
int c; // must use int to distinguish EOF from all valid byte values
int count = 0; // to tell whether a byte was read at all
char ch = 0; // the last byte read
// read all bytes from the input stream until end of file or a newline
while ((c = getchar()) != EOF && c != '\n') {
ch = (char)c;
count++;
}
if (count == 0) {
printf("no characters entered: ");
if (c == EOF) {
printf("end of file or read error\n");
} else {
printf("empty line\n");
}
} else {
printf("last character on line is '%c'\n", ch);
if (c == EOF) {
printf("end of file or input error encountered\n");
}
}
return 0;
}

Strange 10 value gets printed when I print inputed characters by their ASCII decimal code

#include <stdio.h>
#include <stdlib.h>
int main()
{
int end;
while(( end = getchar() ) != EOF ){
printf("%d\n",end);
}
system("pause");
return 0;
}
I want to print the ASCII codes of characters with this code but whenever I run the code after it gets the char from me it prints its ASCII equivalent with decimal 10. For example if I run the code and pass "a", it will print 97 and 10. Why does it print 10, this happens with all other characters too.
Thank you for answers and as a followup question when I add a counter after I input a character counter's value increases by two, why does this happen
#include <stdio.h>
#include <stdlib.h>
int main()
{
int end;
int count=0;
while(( end = getchar() ) != EOF ){
printf("%d\n",end);
count++;
printf("counter is now %d\n",count);
}
system("pause");
return 0;
}
As stated you are printing the ASCII decimal codes for 'a' and '\n' respectively, this is because, in your code, getchar reads all the characters in the stdin buffer, including the newline character which is present because you press Enter.
You can avoid this by simply making it be ignored by your condition:
while((end = getchar()) != EOF && end != '\n'){
printf("%d\n", end);
}
Disclaimer: David Ranieri added a comment with the exact same solution as I was writing my answer (which he kindly deleted) so credit to him as well.
Regarding your comment question and the question edit:
If you don't want the '\n' to interrupt your parsing cycle, you can simply place the condition inside it.
while((end = getchar()) != EOF){
if(end != '\n'){ //now as '\n' is ignored, the counter increases by one
printf("%d\n", end);
count++;
printf("counter is now %d\n",count);
}
}
The reason why the counter is increased by two is, again, because two characters are parsed, whatever character you input and the newline character. As you can see in the sample, if you ignore the '\n', the counter will only increase by one, provided that you only enter one character at a time.
In ASCII, a newline is represented by the value 10.
Anytime you type a sequence of characters and press the ENTER key, you get the ASCII values for the letters/numbers/symbols you types as well as the value 10 for the newline.

C - Ignore spaces in scanf()

I'm trying to make a simple string acquisition. What i need is to write a string from input (stdin), which can contain spaces, and save it without any spaces between words.
So far i've written this simple code which saves everything (also spaces), but i don't know how to make the scanf() ignore the spaces.
int main(){
char str[10];
scanf("%[^\n]s, str);
printf("%s", str;
}
For example:
if my input is: I love C programming! my output should be: IloveCprogramming!
I tried to use %*, used to ignore characters, but without any success.
I also know that i could "rescan" the string once is saved and remove all the spaces, but i need to do this acquisition as efficient as possible, and rescan every string to remove the spaces will increase the computational time a lot (instead of just scanning and ignoring, which has complexity of O(n))
You are using the wrong tool for the job. You need to use getc
And do the following
int ch;
char str[10];
// Loop until either loop reaches 9 (need one for null character) or EOF is reached
for (int loop = 0; loop < 9 && (ch = getc(stdin)) != EOF; ) {
if (ch != ' ' ) {
str[loop] = ch;
++loop;
}
}
str[loop] = 0;
printf("%s", str);
No re-scan required
scanf() is not useful for your purpose, indeed you do not even need a buffer to strip spaces from a line of input: just read bytes one at a time, ignore the spaces, output the others and stop at newline or EOF:
#include <stdio.h>
int main(void) {
int c;
while ((c = getchar()) != EOF) {
if (c != ' ') {
putchar(c);
}
if (c == '\n') {
break;
}
}
return 0;
}
Note also that your code has problems:
the scanf() format string is unterminated
the trailing s is incorrect, the format is simply %[^\n]
it is safer to specify the maximum number of bytes to store into the array before the null terminator: scanf("%9[^\n]", str);
you should test the return value of scanf() to avoid passing an uninitialize array to printf if the conversion fails, for example on an empty line or an empty file.
You could use scanf() as an inefficient way too read characters while ignoring white space, with char c; while (scanf(" %c", &c) == 1) { putchar(c); } but you would be unable to detect the end of line.
If interested in removing other white space from input (in addition to '') you can also incorporate the C library function isspace(.), which tests for the following standard white space characters:
' ' (0x20) space (SPC)
'\t' (0x09) horizontal tab (TAB)
'\n' (0x0a) newline (LF)
'\v' (0x0b) vertical tab (VT)
'\f' (0x0c) feed (FF)
'\r' (0x0d) carriage return (CR)
This example incorporates function using the isspace(.); library function, and provides a method to clear all standard white space from a C string.
int main(void)
{
char string[] = {"this contain's \n whitespace\t"};
int len = strlen(string);
char out[len+1];// +1 for null terminator
//(accommodates when input contains no whitespace)
int count = clean_whitespace(string, out);
return 0;
}
int clean_whitespace(const char *in, char *out)
{
int len, count=0, i;
if((in) && (out))
{
len = strlen(in);
for(i=0;i<len;i++)
{
if(!isspace(in[i]))
{
out[count++] = in[i];
}
}
out[count]=0;//add null terminator.
}
return count;
}
So far i've written this simple code which saves everything (also
spaces), but i don't know how to make the scanf() ignore the spaces.
You're coming at this from the opposite direction of what most new C programmers do. The problem is not usually to make scanf skip spaces, as it does that by default for most types of field, and in particular for %s fields. Spaces are ordinarily recognized as field delimiters, so not only are leading spaces skipped, but also spaces are not read inside fields. I presume that it is because you know this that you are using a %[ field.
But you cannot have your cake and eat it too. The field directive %[^\n] says that the data to be read consist of a run of non-newline characters. scanf will faithfully read all such characters and transfer them to the array you designate. You do not have the option to instruct scanf to avoid transferring some of the characters that you told it were part of the field.
If you want to continue to use scanf then you have two options:
remove the spaces after you read the data, or
read and transfer the space-separated pieces as separate fields.
Another answer already describes how to do the former. Here's how you might do the latter:
int main(void) {
int field_count;
do {
char str[80];
char tail;
field_count = scanf("%79[^ \n]%c", str, &tail));
if (field_count == 0) {
// No string was scanned this iteration: the first available char
// was a space or newline. Consume it, then proceed appropriately.
field_count = scanf("%c", &tail);
if (field_count != 1 || tail == '\n') {
// newline, end-of-file, or error: break out of the loop
break;
} // else it's a space -- ignore it
} else if (field_count > 0) {
// A string was scanned; print it:
printf("%s", str);
if (field_count == 2) {
// A trailing character was scanned, too; take appropriate action:
if (tail == '\n') {
break;
} else if (tail != ' ') {
putchar(tail);
} // else it is a space; ignore it
}
} // else field_count == EOF
} while (field_count != EOF);
}
Things to note:
The 79-character (maximum) field width in the scanf %79[^ \n] directive. Without a field width, there is a serious risk of overrunning your array bound (which must be at least one character longer than the field to allow for a string terminator).
[ is a field type, not a qualifier. s is a separate field type that also handles strings, but has different behavior; no s field is used here.
scanf's return value tells you how many fields were successfully scanned, which can be fewer than are described in the format string in the event that a mismatch occurs between input and format, or the end of the input is reached, or an I/O error occurs. These possibilities need to be taken into account.
In the event that the second field, %c, is in fact scanned, it allows you to determine whether the preceding string field ended because the field width was exhausted without reaching a space or newline, because a space was observed, or because a newline was observed. Each of these cases requires different handling.
Although scanf skips leading whitespace for most field types, %[ and %c fields are two of the three exceptions.
This approach skips space characters (' ') specifically; it does not skip other whitespace characters such as horizontal and vertical tabs, carriage returns, form feeds, etc.. This approach could be adapted to handle those, too, but what is presented is sufficient to demonstrate.
I'm posting this to demonstrate that it is also possible to solve this problem just with scanf.
int main() {
char a[10];
for(int i = 0; i < 10 ; i++){
scanf("%c", &a[i]);
if( a[i] == ' ')
i--;
}
}
the one above simply scans 10 characters without the spaces inbetween.
for(int i = 0; i < 9; i++){
printf("%c,", a[i]);
}
printf("%c", a[9]);
and this is the way to use if you want to replace the spaces with something else, for example: ' , '
If you want the input to consist of more characters, simply define a new variable x and change the 10 into x, and the 9's into x-1
For completeness, here's a simple version using scanf():
#include <stdio.h>
int main(void)
{
char buff[10];
int r;
r = 1;
scanf("%*[ ]");
while (r == 1) {
r = scanf("%9[^ \n]%*[ ]", buff);
if (r == 1) fputs(buff, stdout);
}
putchar('\n');
return 0;
}
What this does:
scanf("%*[ ]"): skip initial whitespace, if any (requested format: non empty sequence of spaces, without storing it in a variable), ignoring the result.
r = scanf("%9[^ \n]%*[ ]", buff): read two requested formats (explained below) and return number of successful conversions.
%9[^ \n]: requested format: up to 9 characters of contiguous text (read up to newline).
%*[ ]: requested format: non empty sequence of spaces, without storing it in a variable.
if (r == 1) fputs(buff, stdout): check if some text was read (1 successful conversion from scanf()). If it was, output it.
This is executed in a loop until a text slice cannot be read anymore. Optionally, the final \n can be read with getchar().
Example execution:
$ ./scanstring
abcd xyz aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa wwwwwwwwwwwwwwwwwwwwwwwwwwww zzzzz 1234567891011121314 !!!
abcdxyzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaawwwwwwwwwwwwwwwwwwwwwwwwwwwwzzzzz1234567891011121314!!!
scanf() manual: https://man7.org/linux/man-pages/man3/scanf.3.html

Scanning the characters properly except '+' and '-'

I am trying to scan an arithmetic expression like : 4+3-2*6*(3+4/2)#
What I tried is following code. It's running fine and scanning each character properly except '+' and '-'.
Why it is not scanning only two particular characters!
void scan(){
int n,tmp,digit_no;
char c;
scanf("%c",&c);
while(c!='#'){
if(isdigit(c))
{
tmp=c;
scanf(" %d",&n);
digit_no=numPlaces(n);
n=(tmp-48)*ipow(10,digit_no)+n;
push_n(n);
n=0;
}
else if(c=='+' || c=='-' || c=='*' || c=='/' || c=='(' || c==')' || c=='=' || c=='^')
push_o(c);
scanf("%c",&c);
}
}
Do not get a char, test for a digit, scan an int and then try to put them together. This fails the code's intent with input like for input like "3-2", "1 23", "1+23" as well explained by #John Bollinger as scanf("%d",&n) is consuming the + -.
Instead put the digit back into stdin and then scan for the int.
if(isdigit(c)) {
ungetc(c, stdin);
scanf("%d",&n); // cannot fail as first character is a digit - may overflow though
push_n(n);
n=0;
}
Also suggest to detect EOF and use is...() functions correctly.
// char c;
// scanf("%c",&c);
int c;
// while(c!='#'){
while((c = fgetc(stdin)) !='#' && c != EOF) {
...
// scanf("%c",&c);
}
Detail: is...() expects an int in the range of unsigned char and EOF. Calling them with a char is a problem when the value is negative.
You are mistaken: scanf() is scanning the '+' and '-'. It is simply scanning them as part of the decimal number that follows.
With your example input, the program first scans a '4', which is a digit. It then proceeds to execute scanf(" %d",&n);, which scans the next two characters, "+3", as the number 3, because fields described by %d may optionally have a leading sign character, either '-' or '+'. The scanning stops at the first '-', since a decimal number cannot contain an internal or trailing '-', and indeed, the '-' is scanned as the next character. You would see different results for '-' or '+' following a two-digit number or a parenthesis.
Overall, your approach to scanning numbers is fundamentally flawed. Not only does it run aground on the optional sign character, but I see no way it can do the right thing when the second-most-significant digit of the number you are trying to read is a '0'. That is, your approach cannot distinguish "401" from "41". You cannot successfully scan the tail of a number as a number in its own right without losing information you need.

Copy input from user and put it on screen

I have been going through The C Programming Language by Brian W. Kernighan and Dennis M. Ritchie and am at Character Input and Output, specifically on File Copying. The example in the book
#include <stdio.h>
int main(void)
{
int c;
c = getchar();
while (c != EOF)
{
putchar(c);
c = getchar();
}
return 0;
}
works perfectly.
But I decided to put my own spin on things and rewrite it a bit:
#define <stdio.h>
int main(void)
{
int c;
printf("Please enter a digit: ");
c = getchar();
while (c != EOF)
{
printf("The digit entered was: ");
putchar(c);
printf("Please enter a digit: ");
c = getchar();
}
return 0;
}
After compiling and executing, the result of my code is:
Please enter a digit: 9
The digit entered was: 9Please enter a digit: The digit entered was:
Please enter a digit: *cursor is here*
The input should be:
Please enter a digit: 9
The digit entered was: 9
Please enter a digit: *the cursor should be here*
Also, I have a little problem understanding EOF. It would be great if someone could help me with these issues.
Thank you!
Most 'terminals' do not send keyboard input to the program 'one key at at time'. Rather, the terminal will wait for the enter key, and then send all keys pressed (up to that point) to the target program. Hence, the question code suffers from getting newlines \n as input, as well as digits.
The code below throws away all non-digit values (but also allows for the EOF value):
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int c;
do {
c=0;
/* Get user input */
printf("Please enter a digit: ");
while(!isdigit(c) && EOF != c)
c = getchar();
/* Produce output. */
if(c == EOF)
printf("\n");
else
printf("The digit entered was: %c\n", c);
} while (c != EOF);
return 0;
}
Compile the above (Linux GCC example: gcc -Wall -o test *.c)
Then execute: (Linux example: ./test)
Please enter a digit: 5
The digit entered was: 5
Please enter a digit: 6
The digit entered was: 6
Please enter a digit: <CTRL-D>
<CTRL-D> usually generates an EOF condition.
Because the ENTER value "\n" (ASCII value 10) will be get by
getchar(c);
so it will do second time of
printf("The digit entered was: ");
printf("Please enter a digit: ");
Well, it's the trouble about the new-line character that you feed the standard input with while handing your piece into the console screen.
Let me ask you this:
With the code that you have said to work perfectly, you probably have tried some input like "Hello!" let's say, or maybe just a single character like "9" as in your example. You have typed down 'H' then 'e' then 'l' ... then '!' and then hit the enter-key, or just '9' and then hit the enter-key.
After that, you had the following on your screen:
Hello!
Hello!
_
The last underscore there is for indicating the flashing cursor. My question is: Why is it there? Why is it not right next to the last '!'?
Same story with the 9, this would be the things on your screen:
9
9
_
Well, here's why: It is because your programme has printed one more character that you cannot see directly, a new-line character '\n'. Proof: If it hadn't printed that, the underscore would flash next to the '!' or '9'.
When you hit your enter-key, you feed the standard input with a new-line character '\n' in addition to whatever you had typed down so far in that session. Standard input gets fed with all that and getchar(); consumes them one by one.
In your code which doesn't work as you had expected, you feed the standard input with '9' '\n', getchar(); first gets the '9' and then '\n', and then it looks for more, but there isn't any more. Only then (when there isn't more) it asks from you for more.
And that's the story...
To get what you were expecting, you should do something else, I won't tell you that directly, it's a good exercise. I can hint you that you should be using another while loop within the one you already have with a condition checking for a '\n' encounter.
EOF is just a special character, or rather a value indicating a special case of being at the End Of File. For standard input, I guess it can be issued with the CTRL + D key combination on Linux, it is CTRL + Z on Windows. Using that combination and then hitting enter should get you out of that outer loop.
You're being tripped up by a trailing newline in your input; when you type 9 and hit Enter, the input stream that your code reads from will contain the encodings for two characters, the 9 and a newline (in ASCII, it would be the sequence of values [57,10]) . Here's how it breaks down:
Code prompts you to enter a digit
You type 9 and hit Enter
Input stream now contains the characters {'9', '\n'};
getchar returns the next available character from the input stream, which is '9'
'9' is not equal to EOF, so you print the digit and prompt for the next character
getchar returns the next available character from the input stream, which is '\n'
'\n' is not equal to EOF, so you print the character and prompt for the next character
The input stream is now empty, so getchar blocks until you type something else.
You can fix this relatively easily:
#include <ctype.h>
...
while (c != EOF)
{
printf("The digit entered was: ");
putchar(c);
printf("Please enter a digit: ");
do
{
c = getchar();
} while ( isspace( c ));
}
That last little do loop will read characters from the input stream until it sees something that isn't a newline or other whitespace character. You can add an additional check to make sure the character entered really was a digit [0-9]:
while (c != EOF)
{
printf("The digit entered was: ");
putchar(c);
do
{
printf("Please enter a digit: ");
do
{
c = getchar();
} while ( isspace( c ));
if ( !isdigit( c ))
printf( "%c is not a digit!\n" );
} while ( !isdigit( c ));
}
Now, something to be aware of; what you're storing in c is not the value 9, but the encoding for the character '9', which in ASCII is the integer value 57. If you want to store the value 9 in c, you'll have to do something different.

Resources