How can you read numbers from keyboard until CTRL+D is pressed? - c

As the title says, I need to read numbers until CTRL+D is pressed. I was thinking about getchar() but i need to separate negative numbers from positive ones and i think it will be quite complicated like that.

you can use scanf to try to read a number (here I suppose int), and getchar (or equivalent) to both bypass non valid characters for a number and to detect EOF :
#include <stdio.h>
int main()
{
for (;;) {
int v;
if (scanf("%d", &v) == 1)
printf("read %d\n", v);
else
// bypass invalid char
if (getchar() == EOF)
break;
}
puts("done");
}
Compilation end executions :
pi#raspberrypi:/tmp $ gcc -pedantic -Wall -Wextra c.c
pi#raspberrypi:/tmp $ ./a.out
12 aze -23
read 12
read -23
3 e
read 3
done
pi#raspberrypi:/tmp $
Under raspberrypi I enter two consecutive control-d to indicate EOF
Using echo to also produce the EOF :
pi#raspberrypi:/tmp $ echo "123 aze -23 " | ./a.out
read 123
read -23
done
pi#raspberrypi:/tmp $
When there is an invalid character I chosen to read only one character, it is also possible to bypass the rest of the line, or stop to read numbers, it is a choice.

Related

Echo input into output, at the right place

I want to insert the input given to a program into its output, in the moment it is read.
For instance, given the program:
#include <stdio.h>
int main() {
double x, y;
printf("Soma de dois números:\n");
printf("Digite o primeiro número: ");
scanf("%lf", &x);
printf("Digite o segundo número: ");
scanf("%lf", &y);
double soma = x + y;
printf("%lf + %lf = %lf\n", x, y, soma);
return 0;
}
when it is run with input redirection, I want the input inserted into the output, like the following:
$ echo -e "10\n25\n" | ./a.out
sum of two numbers
first number: 12
second number: 25
12.000000 + 25.000000 = 37.000000
Is there any library or tool to help me with that?
Edited Context: I intend to use this for correcting program exercises in a programming course. I want to see/show the program input and output as if it were run in an interactive console with the input being typed interactively, although the input is redirect from a text file.
As I noted in a comment:
There isn't an easy way to do that. The problem is that when you type at the terminal, the terminal driver echoes the characters typed. When you have I/O redirection (from a pipe or a file), the terminal driver is not involved, and neither the disk driver nor the pipe driver echoes to standard output.
One option might be to use a pseudo-terminal for the input to your program — but I've not tried it so that might not work. It's also fairly fiddly to set up (though there might well be a utility available on Linux, in particular, to do the job).
Or you could test to see whether the input is a terminal, doing nothing special if it is a terminal, and echoing the result of the input if it is. POSIX function isatty() determines whether the given file descriptor is a terminal or not.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
printf("Enter a number: ");
double d;
if (scanf("%lf", &d) != 1)
{
fprintf(stderr, "Failed to read a number!\n");
exit(EXIT_FAILURE);
}
if (!isatty(STDIN_FILENO))
printf("%lf\n", d);
printf("You entered: %lf\n", d);
return 0;
}
With that saved as source file tty47.c, I can run:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -fno-common tty47.c -o tty47
$ tty47
Enter a number: 2.718282
You entered: 2.718282
$ echo "3.141593" | tty47
Enter a number: 3.141593
You entered: 3.141593
$ tty47 <<<'1.618034'
Enter a number: 1.618034
You entered: 1.618034
$
The first run accepts the input I type at the terminal, and that is echoed by the terminal driver. The other two runs know that the input comes from a pipe and a file respectively, and they echo the input. Note that the echo is not guaranteed to be exactly what the user entered — I cheated by typing numbers with 6 decimal places. Use fewer places and you get trailing zeros; use more and the result is rounded. You'll have to decide whether that matters.
An alternative strategy would read the input using getchar() or equivalent and echo each character with putchar() or equivalent if the input is not a terminal, and then use sscanf() to parse the data. That's definitely fiddlier.

Not sure why optimizer is optimizing my method incorrectly

I'm new to C (so there's every good chance I'm doing something fundamentally wrong or bad), and working on a kattis problem, https://open.kattis.com/problems/abc.
I'm running in to fun with what appears to be the GCC optimiser and I'm trying to understand why or what I'm doing wrong. Here's the simplest replication case I can come up with:
#include <stdio.h>
#include <string.h>
int lookup(char input){
// This will return 2 on invalid input. Not ideal, but we don't have to worry about invalid inputs like that
fprintf(stderr, "Asked to compare: %s\n", &input);
if (strcmp("A", &input) == 0){
//fprintf(stderr, "It's an A\n");
return 0;
} else if (strcmp("B", &input) == 0){
//fprintf(stderr, "It's a B\n");
return 1;
} else {
return 2;
};
}
int main(void){
char input[3];
if (scanf("%3s", input) != 1){
fprintf(stderr, "Something went wrong reading input\n");
return -1;
};
printf("Desired Order: %s\n", input);
printf("%d %d %d\n", lookup(input[0]),
lookup(input[1]),
lookup(input[2])
);
}
An example input file for triggering this bug has a single line:
CAB
If I compile with without optimisations:
$ cc -std=gnu11 -static -lm simple.c -o simple && cat input | ./simple
Desired Order: CAB
Asked to compare: B
Asked to compare: A
Asked to compare: C
2 0 1
With optimisations enabled, note it's falling through to the else section:
$ cc -O2 -std=gnu11 -static -lm simple.c -o simple && cat input | ./simple
Desired Order: CAB
Asked to compare: B
Asked to compare: A
Asked to compare: C
2 2 2
Things I've noticed so far:
If I uncomment the fprintf after the strcmp("A", &input), the code works fine even with optimisations enabled (that's what got me wondering about optimisations breaking my code in the first place).
If I uncomment the fprintf after the strcmp("B", &input) the code fails when optimised.
If I comment out the "Desired Order:" printf, the code works fine even with optimisations.
char input[3];
but you wrote three characters to it. Need 1 more for null terminator.
char input[4];
And here we have
fprintf(stderr, "Asked to compare: %s\n", &input);
No. That's a character not a string so we want
fprintf(stderr, "Asked to compare: %c\n", input);
and we also have
strcmp("A", &input) == 0
but input is a char so we want
'A' == input
and the same for 'B'

No compiler errors, but there is a bug somewhere

I compiled with "gcc -ansi -pedantic -W -Wall -o ". I only get 2 errors when I compile, and here they are:
easter_eggs.c: In function ‘main’:
easter_eggs.c:23:18: warning: multi-character character constant [-Wmultichar]
if (prompt == 'egg1')
^
easter_eggs.c:23:4: warning: comparison is always false due to limited range of data type [-Wtype-limits]
if (prompt == 'egg1')
when I run the program and hit S, it displays the top 2 printf statements 2 times each. If I type anything and press enter nothing happens it just goes back to the prompt. Even if I type egg1, it still goes back to prompt. Here is the source:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char first_option;
char prompt[16];
system("clear");
system("toilet -f future -F gay Easter Eggs");
printf("\nFind all the easter eggs and you win. Simple enough.\n");
printf("Hit S to start and Q to quit\n");
scanf("%c", &first_option);
if (first_option == 's')
{
while (1)
{
printf("To exit hit Ctrl + C\n");
printf("You must find all easter eggs simply by typing stuff in the prompt below: \n");
memset(prompt, 0, sizeof(prompt));
scanf("%16s", prompt);
getchar();
if (!strcmp(prompt, "egg1"))
{
printf("Found 1\n");
}
}
}
if (first_option == "q")
{
exit(0);
}
else
{
printf("Invalid input. Press Enter to continue\n");
getchar();
main();
}
return 0;
}
Edit 1: I have edited the source
Edit 2: Changed the source again. This time I use strcmp() to compare the strings, not ==
Last Edit: I managed to make it work. Also updated the source so that it works. Thx to all for being patient with me. Havn't slept in idk how many days. :/
Read more about C programming. You are confused about char and strings.
If you want to read a word as a a string of at most 16 bytes with a terminating null byte, use e.g.
char prompt[16];
memset (prompt, 0, sizeof(prompt));
if (scanf("%15s", prompt)<1) return;
if (!strcmp(prompt, "egg1")) {
/// found
Also, you are right to compile with -Wall. But compile also with debugging information and extra warnings:
gcc -Wall -Wextra -g easter_eggs.c -o easter_eggs
and learn how to use the gdb debugger.
Read also the man pages (type man man in your Linux terminal) of scanf(3) & strcmp(3)
When you compare a char variable, you have to compare it with a char.
As the compiler told you, you have a multi-character here.
strcmp() will help you.
As mentioned in other comments, Read C. Below are some suggestions
To store string in C, You must use char[] or char * after allocating memory.
You cannot use == operator to compare strings. Use strcmp() instead.

for loop not executing any instructions outside of loop

For reference, I'm copying this example (nearly) letter for letter from page 18 in The C Programming Language, Second Edition.
#include <stdio.h>
/*count characters in input, 2nd version*/
main(){
double n;
for (n = 0; getchar() != EOF; ++n)
;
printf("%.0f\n", n); /*this never prints*/
}
I wasn't sure if it was my version of gcc (I'm a noob):
% gcc --version
gcc (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5
Copyright (C) 2010 Free Software Foundation, Inc.
Because
for (n = 0; getchar() != EOF; ++n)
printf("%.0f",n); /*returns 0123456...n*/
I tried printing "foo" instead of value n, just to see. It still isn't printing.
What am I missing here? I don't like moving ahead while ignoring little problems like these.
=====================================
EDIT
So the end result should be:
% gcc ./counter.c -o ./counter
% ./counter
foo
3
Right now, this is the output from the first snippet:
% ./counter
foo
0123
And the second one:
% ./counter
foo
^C
%
If you are on an OSX or linux box, you need to type Ctrl+D on its own line to generate an EOF character. On Windows, Ctrl+Z on its own line. Don't type Ctrl+Z on a unix box because that will just send your proces to the background.
You are typing Ctrl+C which is break, and will send a SIGTERM to your program.
On my mac, I get:
$ ./foo
hello
6D
Or if you don't want to signal the EOF condition, use echo and a pipe:
$ echo "hello" | ./foo
6
Note that the EOF has to be on its own line. a ^D is printed, and then 6 overwrites the ^, so it looks like the output is 6D.
Of course, in the two above examples, the characters being counted are h e l l o \n. If you don't want a newline, do this:
$ echo -n "hello" | ./foo
5
You shouldn't have that semi-colon after the for. That means the only thing in your loop is an empty statement.
Actually, David is correct. The empty statement is the only thing in the loop, but that's fine. It will count the number of characters. Then, outside the loop, it will print the total.
This demo shows that it works as intended (6-character input results in printing 6). However, I would use braces, or keep the indentation as in the original for clarity.

Unexpected result from printf

#include<stdio.h>
int main()
{
printf("He %c llo",65);
}
Output: He A llo
#include<stdio.h>
int main()
{
printf("He %c llo",13);
}
Output: llo. It doesnt print He.
I can understand that 65 is ascii value for A and hence A is printed in first case but why llo in second case.
Thanks
ASCII 13 is carriage return, which on some systems simply moves the cursor to the beginning of the line you were just on.
Further characters then wipe out the earlier text.
Man ascii:
Oct Dec Hex Char
015 13 0D CR '\r'
Character 13 is carriage return so it prints He then returns to the beginning of the line and prints the remining llo.
It's just being rendered strangely due to the nature of a carriage return*. You can see the characters that are output, by piping to another tool such as xxd:
$ gcc b.c && ./a.out | xxd
0000000: 4865 200d 206c 6c6f He . llo
$ gcc c.c && ./a.out | xxd
0000000: 4865 2041 206c 6c6f He A llo
* See Wikipedia:
On printers, teletypes, and computer terminals that were not capable of displaying graphics, the carriage return was used without moving to the next line to allow characters to be placed on top of existing characters to produce character graphics, underlines, and crossed out text.

Resources