Help with scanf behaving differently on Big Endian system - c

My code is supposed to read a line from the user, if the line starts with "output" then it prints out "Line is output" and waits for the user to enter another line.
If the line starts with "input" it prints out "Line is input" and terminates.
My code works fine on an Intel PC, however on a Debian SPARC it seems the scanf doesnt wait for input after the first time and just reads in an empty line or something infinitely.
Where am I going wrong here?
#include <stdio.h>
#include <string.h>
int main()
{
char buf[9000];
char key[5];
char *p=buf;
int readMore=1;
while(readMore)
{
//read in one line from stdin into buffer
scanf("%[^\n]",buf);
fflush(stdin);
sscanf(p, "%s",key); //get key from buffer
printf("Key:%s\n",key); //print key
if (strcmp("output",key)==0)
{
printf("Line is output\n");
}
if (strcmp("input",key)==0)
{
readMore=0;
printf("Line is input\n");
fflush(stdin);
getchar();
return 0;
}
key[0]=0;
buf[0]=0;
} //end while
return 0;
}
Fixed like this:
......
int bytes_read;
int nbytes = 100;
while(readMore)
{
/* These 2 lines are the heart of the program. */
p = (char *) malloc (nbytes + 1);
bytes_read = getline (&p, &nbytes, stdin);
....

This is not an endian issue. This is about how buffering of standard input is performed on the different platforms. Basically, you can't use fflush() on standard input (or any other input stream) - the C Standard says that doing so is undefined.

Related

Why doesn't it wait for me to input string after I exit the loop using CTRL+D

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char c, char_array[100];
int i = 0;
printf("Enter characters (press CTRL+D to end):\n");
while(fgets(char_array+i,sizeof(char_array)-i,stdin)) {
i = i + strlen(char_array+i);
if(char_array[i-1] == EOF)
break;
}
char_array[i-1] = '\0';
strtok(char_array,"\n");
printf("\nEnter a string:\n");
char string[100];
fgets(string,sizeof(string),stdin);
printf("\nCharacter Array: %s\n", char_array);
printf("String: %s\n", string);
return 0;
}
This is the code and I have tried many different variations(simpler) but it always has the same problem... I enter the characters, press CTRL+D and it ends without waiting for me to input a string. please help
I tried everything I could but I just cant make it work and my friends cant too... I have and exam and I need this to be done in 3 days max so I need all the help I can get.
fgets() returns NULL when the stream is closed. On Linux Ctrl-D will flush the terminal buffer if it's not empty (but fgets() will not return as it remains line buffered), and a 2nd Ctrl-D is required to trigger the EOF state of the stream.
You also want to terminate the loop if the array is full otherwise it's an infinite loop:
#define ARRAY_LEN 100
//...
while(i < ARRAY_LEN - 1 && fgets(char_array + i, ARRAY_LEN - i,stdin)) {
fgets() will not emit EOF as part of the string being read, so this is simply incorrect, and as stdin is line buffered the last character is either \n or whatever if the last character was read if the buffer is full which could be -1 or 0xff (whatever char is signed or not but that's still wrong):
if(char_array[i-1] == EOF)
break;
The next line:
char_array[i-1] = '\0';
strips the last character which is either \n or whatever we read last if the array is full (i.e. data loss).
As the input stream is in the EOF state the 2nd fgets() will return NULL. You can clear that state with clearerr(stdin) before calling fgets() to get the 2nd string. If the stream indeed ended, as in, echo "hello world" | ./your_program, the 2nd fgets() with return NULL again of course.
I suggest you use a blank line to signify end of input:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARRAY_LEN 100
int main() {
printf("Enter characters (empty line to end):\n");
char char_array[ARRAY_LEN];
for(size_t i = 0; i < ARRAY_LEN - 1; i += strlen(char_array)) {
if(!fgets(char_array + i, ARRAY_LEN - i, stdin)) {
printf("fgets() failed\n");
return 1;
}
if(char_array[i] == '\n') {
char_array[i] = '\0';
break;
}
}
strtok(char_array, "\n");
printf("Enter a string:\n");
char string[ARRAY_LEN];
char *rv = fgets(string,sizeof(string),stdin);
printf("Character Array: %s\n", char_array);
printf("String: %s\n", string);
}
and example session:
Enter characters (empty line to end):
hello
world
Enter a string:
friend
Character Array: hello
String: friend
With stdio streams, error/eof is sticky -- that is, once an error or eof condition has occurred, further operations on the FILE * will continue to return EOF or NULL (depending on the function), rather than trying to read or write anything further.
To reset the eof state on the FILE *, you need to call clearerr(stdin). Once you do that, you can read additional input from the terminal.

How to read/write non ascii characters?

I am trying to input a file and have it be printed each character at a time but some characters are ignored.
I'm assuming that that's because they are non ascii chars and the fgets doesn't know what to do with them since the buffer is made of chars.
int main() {
while(1)
{
char str[50];
if (fgets(str, 50, stdin) == NULL)
{
exit(0);
}
for(int i = 0; str[i] != '\n' ; i++)
{
printf("%lc", str[i]);
}
printf("\n");
}
return 0;
}
I have a file with
ALICE’SE’E’E’E’E’E’
but my code outputs it as
ALICESEEEEEE
if you use fgets(), that will probably have some undefined behaviour with input characters like \0, as they are internally used by the string functions to mark the end of the data in a string.
fgets()is a text oriented function that reads input until it finds a new line character \n. It then places a \0 after it, so you know where the string ends.
But with binary data, you can get control characters, even null characters in the middle of the data stream, making sometimes characters to dissapear on output (because they have been read, but your code doesn't go further when some of these are encountered later on writing).
If you want to allow all binary characters, you have several approaches here:
Use the binary stream counterparts from stdio: fread(3) and fwrite(3) functions allow you to read binary data as well as text:
#include <stdio.h>
#include <stdlib.h> /* for EXIT_* constants and exit() */
#define N (8192) /* buffer size (guessed, probably not optimum) */
int main()
{
ssize_t n;
char buffer[N];
while((n = fread(buffer, sizeof buffer[0], N, stdin)) > 0) {
ssize_t nout = fwrite(buffer, sizeof buffer[i], n, stdout);
if (nout != n) { /* error */
fprintf(stderr, "Error writing stdout\n");
exit(EXIT_FAILURE);
}
}
exit(EXIT_SUCCESS);
} /* main */
Use the simple Kernighan & Ritchie's sample from "The C programming language" book (I've added some error processing code):
#include <stdio.h>
#include <stdlib.h> /* idem. */
int main()
{
while((c = fgetc(stdin)) != EOF)
if (fputc(stdout) == EOF) {
fprintf("fputc error\n");
exit(EXIT_FAILURE);
}
}
if (ferror(stdin)) {
fprintf("fgetc error\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
} /* main */
or use the standard UNIX system calls:
#include <unistd.h> /* for prototypes for read()/write() syscalls */
#include <stdio.h>
#include <stdlib.h>
#define N (8192) /* guessed buffer size */
int main()
{
char buffer[N];
ssize_t n;
while ((n = read(0, buffer, sizeof buffer)) > 0) {
ssize_t nout;
nout = write(1, buffer, sizeof buffer));
if (nout != n) {
fprintf(stderr, "write: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
}
if (n < 0) {
fprintf(stderr, "read: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
} /* main */
but beware that probably the most efficient code you'll get can be the original character oriented sample from the K&R book, as stdio will select an optimum buffer size that will make it run faster, despite of the higher number of loop executions.
note
Anyway, your output will be far to be what you want, as some control characters are not output to the terminal, but interpreted as control characters (most popular being \n, which makes the terminal to continue on the next line) You have also to deal with this.
Even if you read multibyte characters as single byte, you can process those with the examples given, as a character that uses two bytes, will be read as two, but on printing, those will become the single char the terminal should display. As long as you apply no transformation to the data flow, there will be no difference in output with the sample code snippets you have above this.
You are using fgets, which deals with chars, and a char array (char str[50]).
But a printf formatter %lc which is for wide char.
If you want to input wide char, you need to use fgetws, and an array of type( wchar_t str[50])

Clear buffer stdin

Hello Stackoverflow community, I have a problem with this code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAX_SIZE 50
int main()
{
char *s = malloc(sizeof(char)*MAX_SIZE);
do{
int r = read(STDIN_FILENO, s, MAX_SIZE);
if(r==-1) printf("error");
else{
write(STDERR_FILENO, s, MAX_SIZE);
}
while(getchar()!='\n');
} while(strcmp(s,"end\n")!=0);
free(s);
return 0;
}
The problem is that it produces me a wrong output, stdin doesn't results "clean" at each iteration of the 'do while'. I know that on windows i must use fflush(stdin) but watching on internet i saw that this function is not portable for linux. i use linux, and always watching on internet i saw that many people say the solution is while(getchar()!='\n); instead of fflush(stdin), but the problem is not resolved... Can you explain me why?
Problems that I see:
You are passing the wrong argument to write. Instead of
write(STDERR_FILENO, s, MAX_SIZE);
it should be
write(STDERR_FILENO, s, r); // Write the number of characters that were read
// not MAX_SIZE
The strategy to skip till the end of the line is not well thought out. You have:
int r = read(STDIN_FILENO, s, MAX_SIZE);
if(r==-1) printf("error");
else{
write(STDERR_FILENO, s, MAX_SIZE);
}
while(getchar()!='\n');
First of all, read will not stop reading when it encounters a newline. It will read up to MAX_SIZE characters. It will gobble up as many newlines as it can in the process. What you need to do is use fgets() instead.
char* cp = fgets(s, MAX_SIZE, stdin);
if ( cp == NULL )
{
// If fgets fails, you probably reached the end of the file.
break;
}
fprintf(stderr, "%s", s);
The line
while(strcmp(s,"end\n")!=0);
will lead to undefined behavior if you use read to read the data from a file since read does not automatically add a terminating null character to s. Using fgets avoids that problem.
Also, since you know the size of the array at compile time, you can use:
char s[MAX_SIZE];
instead of using malloc to allocate memory at run time.
FYI, an equivalent C++ program
#include <iostream>
#include <string>
int main() {
for (std::string line; std::getline(std::cin, line); ) {
if (line == "end")
break;
}
}

Reading a text file in C, stopping at multiple points, breaking it into sections

I have a program that has a text file that is variable in length. It must be capable of being printed in the terminal. My problem is that if the code is too large, part of it becomes inaccessible due to the limited scroll of terminal. I was thinking of having a command executed by a character to continue the lines after a certain point, allowing the user to see what they needed, and scroll if they needed. However the closest I have come is what you see here, which prints the text file one line at a time as you press enter. This is extremely slow and cumbersome. Is there another solution?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
FILE *audit;
audit = fopen("checkout_audit.txt", "r");
char length_of_code[60000];
int ch;
while ((ch = fgetc(audit)) != EOF)
{
fgets(length_of_code, sizeof length_of_code, audit);
fprintf(stdout, length_of_code, audit);
getch();
if (ferror(audit))
{
printf("This is an error message!");
return 13;
}
}
fclose(audit);
return 0;
}
The libraries are included as I tried various methods. Perhaps there is something obvious I am missing, however after looking around I found nothing that suited my needs in C.
You can keep a count of something like num_of_lines and keep incrementing it and when it reaches some number(say 20 lines) then do a getchar() instead of doing it for each line.
Make sure you don't use feof() as already suggested. Just for the purpose of how it can be done I am showing the below snippet.
int num_of_lines = 0;
while(!feof(fp))
{
// fgets();
num_of_lines++;
if(num_of_lines == 20)
{
num_of_lines = 0;
getch();
}
}
Putting the same thing in your code:
int main()
{
FILE *audit;
audit = fopen("checkout_audit.txt", "r");
char length_of_code[60000];
int num_of_lines = 0;
int ch;
while (fgets(length_of_code, sizeof length_of_code, audit) != NULL)
{
fprintf(stdout, length_of_code, audit);
if (ferror(audit))
{
printf("This is an error message!");
return 13;
}
num_of_lines++;
if(num_of_lines == 20)
{
num_of_lines = 0;
getch();
}
}
fclose(audit);
return 0;
}
From the man page of fgets()
fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s.
Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte is stored after the last character in the buffer.
So char length_of_code[60000]; is not a better option.
Try to set the size of array to optimum value which in most case is 80.
Also as fgets fetches line by line you will have to output line by line untill EOF
EDIT:
1. 2nd argument to fprintf should be the format specifier and not length
2. 3rd arg should be a string and not the file pointer
fprintf(stdout, "%s", length_of_code);
Code Snippet:
while (fgets(length_of_code, sizeof(length_of_code), audit))
{
fprintf(stdout, "%s", length_of_code);
getch();
if (ferror(audit))
{
printf("This is an error message!");
return 13;
}
}

C Dynamic Array based on input from console

I am writing a program that stores input from the console. To simplify it lets say I need to output what was wrote to the console.
So I have something like this:
int main()
{
char* input;
printf("Please write a bunch of stuff"); // More or less.
fgets() // Stores the input to the console in the input char*
printf(input);
}
So that is it in more or less. Just trying to give you the general idea. So what if they input something the size of 999999999999. How can I assign a char* to be that size dynamically.
#include <stdio.h>
int main(void)
{
char input[8192];
printf("Please type a bunch of stuff: ");
if (fgets(input, sizeof(input), fp) != 0)
printf("%s", input);
return(0);
}
That allows for a rather large space. You could check that you actually got a newline in the data.
If that's not sufficient, then investigate the POSIX 2008 function getline(), available in Linux, which dynamically allocates memory as necessary.
Here's an example - you need to validate the input and make sure you don't overflow your buffer. In this example, I discard anything over the max length and instruct the user to try again. Another approach would be allocating a new (larger) buffer when that happened.
fgets() second argument is the maximum number of characters you will read from the input. I'm actually accounting for the \n in this example and getting rid of it, you may not want to do so.
#include <stdio.h>
#include <string.h>
void getInput(char *question, char *inputBuffer, int bufferLength)
{
printf("%s (Max %d characters)\n", question, bufferLength - 1);
fgets(inputBuffer, bufferLength, stdin);
if (inputBuffer[strlen(inputBuffer) -1] != '\n')
{
int dropped = 0;
while (fgetc(stdin) != '\n')
dropped++;
if (dropped > 0) // if they input exactly (bufferLength - 1) characters, there's only the \n to chop off
{
printf("Woah there partner, your input was over the limit by %d characters, try again!\n", dropped );
getInput(question, inputBuffer, bufferLength);
}
}
else
{
inputBuffer[strlen(inputBuffer) -1] = '\0';
}
}
int main()
{
char inputBuffer[10];
getInput("Go ahead and enter some stuff:", inputBuffer, 10);
printf("Okay, I got: %s\n",inputBuffer);
return(0);
}

Resources