Issues with 'read' system function - c

I was writing a programm which must read a word, which is separated from others by a ' ' or \n, from a file (I decided to use 'read' system function for it) and faced up an issue with it.
In particular, as it is written in manual, 'read' must return 0 when there is nothing else to read (EOF is reached), but in my case it returns \n (I checked the ASCII code of returned symbol and it's 10which is of \n and checked my program a number of times and it always returns the same). Here's the code
char *read_word_from_file(int fd, int *flag)
{
int i = 0;
char ch, *buf = NULL;
if (!read(fd, &ch, 1)) { //file is empty
*flag = 1;
return NULL;
}
while (ch != ' ' && ch != '\n') {
if (!(buf = (char *) realloc(buf, i + 1))) goto mem_err;
buf[i++] = ch;
if (!(read(fd, &ch, 1))) {
*flag = 1;
break;
}
}
buf[i] = '\0';
return buf;
mem_err:
perror("realloc");
exit(1);
}
(flag variable is used to indicate the EOF for the outer function, which calls this one) So, my question is "is such behavior is normal, or I made a mistake somewhere?"
P.S. - Off-topic question, how do you make a part of text(a single word) shadowed like a code samples?

gedit simply doesn't show newlines in files. Why is there a newline in your file? Depends on how you created that file. If you used for example puts("M"); then you should understand that puts() adds a newline. If you created it with an editor, you should understand that editors usually write complete lines ending in a newline.
– Jens

Related

How to read multiple lines of string from stdin in C?

I am a novice in C programming. Suppose I want to read multiple lines of string from stdin. How can I keep reading until a line only containing EOL?
example of input
1+2\n
1+2+3\n
1+2+3+4\n
\n (stop at this line)
It seems that when I hit enter(EOL) directly, scanf won't execute until something other than just EOL has been entered. How can I solve that problem?
I'll be really grateful if someone can help me with this. Thank you.
If you want to learn C, you should avoid scanf. The only use cases where scanf actually makes sense are in problems for which C is the wrong language. Time spent learning the foibles of scanf is not well spent, and it doesn't really teach you much about C. For something like this, just read one character at a time and stop when you see two consecutive newlines. Something like:
#include <stdio.h>
int
main(void)
{
char buf[1024];
int c;
char *s = buf;
while( (c = fgetc(stdin)) != EOF && s < buf + sizeof buf - 1 ){
if( c == '\n' && s > buf && s[-1] == '\n' ){
ungetc(c, stdin);
break;
}
*s++ = c;
}
*s = '\0';
printf("string entered: %s", buf);
return 0;
}
to read multiple lines of string from stdin. How can I keep reading until a line only containing EOL?
Keep track of when reading the beginning of the line. If a '\n' is read at the beginning, stop
getchar() approach:
bool beginning = true;
int ch;
while ((ch = getchar()) != EOF) {
if (beginning) {
if (ch == '\n') break;
}
// Do what ever you want with `ch`
beginning = ch == '\n';
}
fgets() approach - needs more code to handle lines longer than N
#define N 1024
char buf[N+1];
while (fgets(buf, sizeof buf, stdin) && buf[0] != '\n') {
; // Do something with buf
}
If you need to read one character at a time then you can with either getchar or fgetc depending upon whether or not you're reading from stdin or some other stream.
But you said you were reading strings, so I'm assuming fgets is more appropriate.
There are primarily two considerations:
maximum line length
whether or not to handle Windows versus non-Windows line endings
Even if you are a beginner--and I won't go into #2 here--you should know you can defend against it. I will at least say that if you compile on one platform and read from stdin from a redirected file from another platform, then you might have to write a defense.
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main (int argc, char *argv[]) {
char buf[32]; // relatively small buf makes testing easier
int lineContinuation = 0;
// If no characters are read, then fgets returns NULL.
while (fgets(buf, sizeof(buf), stdin) != NULL) {
int l = strlen(buf); // No newline in buf if line len + newline exceeds sizeof(buf)
if (buf[l-1] == '\n') {
if (l == 1 && !lineContinuation) {
break; // errno should indicate no error.
}
printf("send line ending (len=%d) to the parser\n", l);
lineContinuation = 0;
} else {
lineContinuation = 1;
printf("send line part (len=%d) to the parser\n", l);
}
}
printf("check errno (%d) if you must handle unexpected end of input use cases\n", errno);
}

C Programming , getc() , stdin , file redirection

My assignment is to redirect a text file and do all sorts of operations on it , everything is working except I have a little problem :
so the main function that reads input is getline1():
char* getline1(){
char *LinePtr = (char*)malloc(sizeof(char*)*LINE);
int i = 0;
for ( ; (*(LinePtr+i) = getc(stdin)) != '\n' ; i++){}
*(LinePtr+i) = '\0';
return LinePtr;
}
it returns a pointer to char array of a single line,
so we know that a new line saparates with '\n' char,
previous problem I had is when I wrote the getline1() function like this :
for (int i = 0 ; Line[i] != '\n' ; i++){
Line[i] = getc(stdin);
}
as it logically it may be authentic the getc() is a streaming function and I saw online answers that this will not work didn't quite understand why.
anyway the big issue is that I need to know how many lines there are in the text so I can stop reading values , or to know from getline1() function that there is no next line left and Im done.
things we need to take for account :
1.only <stdio.h> <stdlib.h> need to be used
2.Im using Linux Ubuntu and gcc compiler
3.the ridirection goes like ./Run<input.txt
also I understand that stdin is a file pointer , didn't found a way that this can help me.
Thank you ,
Denis
You should check for the EOF signal in addition to the newline character, you should also check for that your index-1 is always smaller than LINE to avoid overflow and also save space for the NULL terminator.
#define LINE 100
char *my_getline(void)
{
size_t i = 0;
char *str = NULL;
int c = 0;
if ((str = malloc(LINE)) == NULL)
{
fprintf(stderr,"Malloc failed");
exit(EXIT_FAILURE);
}
while (i+1 < LINE && (c = getchar()) != EOF && c != '\n') /* Saving space for \0 */
{
str[i++] = c;
}
str[i] = '\0';
return str;
}
Thanks for everybody , I just made another function to count line this was the only lazy option available :)
static void linecounter(){
FILE *fileptr;
int count = 0;
char chr;
fileptr = fopen("input.txt", "r");
chr = getc(fileptr);
while (chr != EOF){
if (chr == '\n'){count = count + 1;}
chr = getc(fileptr);}
fclose(fileptr);
count_lines = count;}

Append data from an array to a char variable in C

i have a program that i'm writing, and i need to read in a configuration file. if you can't tell by the way it's written it is a placeholder for another program, it opens the second program in its memory space. I have the readline function all set up, but my "main" operation will only support a variable for arguments (unless im incorrect), like this: "arg1 arg2 arg3..." I have seen things on the net like 'strcat' and others, but since im not so versed in C these seem to only add a single character. my needed solution would be:
char args[ 10 ];
FILE *fp=fopen("file.cfg","r");
void readLine(FILE* file, char* line, int limit)
{
int i;
int read;
read = fread(line, sizeof(char), limit, file);
line[read] = '\0';
for(i = 0; i <= read;i++)
{
if('\0' == line[i] || '\n' == line[i] || '\r' == line[i])
{
line[i] = '\0';
break;
}
}
if(i != read)
{
fseek(file, i - read + 1, SEEK_CUR);
}
}
int main(void)
{
_spawnl( P_OVERLAY, "prog1.exe", "prog1.exe", args, NULL );
return 0;
}
the 'args' variable in 'int main(void)' would need to be the one that is = line[i].
unless a complete rewrite would be nessecary.
Also b4 you flame me, i dont want a loop in main, because this program just calls another, then dies. A loop might make it call an infinite number of the same program, and... well that would be bad. thanks in advance!

Using fgetc to pass only part of a text file to a buffer

I have the following text file:
13.69 (s, 1H), 11.09 (s, 1H).
So far I can quite happily use either fgets or fgetc to pass all text to a buffer as follows:
char* data;
data = malloc(sizeof(char) * 100);
int c;
int n = 0;
FILE* inptr = NULL;
inptr = fopen("NMR", "r");
if(NULL == fopen("NMR", "r"))
{
printf("Error: could not open file\n");
return 1;
}
for (c = fgetc(inptr); c != EOF && c != '\n'; c = fgetc(inptr))
{
data[n++] = c;
}
for (int i = 0, n = 100; i < n; i++)
{
printf ("%c", data[i]);
}
printf("\n");
and then print the buffer to the screen afterwards. However, I am only looking to pass part of the textfile to the buffer, namely:
13.69 (s, 1H),
So this means I want fgetc to stop after ','. However, this means the that the text will stop at 13.69 (s, and not 13.69 (s, 1H),
Is there a way around this? I have also experimented with fgets and then using strstr as follows:
char needle[4] = ")";
char* ret;
ret = strstr(data, needle);
printf("The substring is: %s\n", ret);
However, the output from this is:
), 11.09 (s, 1H)
thus giving me the rest of the string which I do not want. It's an interesting one and if anyone has any tips it would be much appreciated!
If you know that the closing parenthesis is the last character you want, you can use that as your stopping point in the fgetc() loop:
char data[100]; //No need to dynamically allocate if we know the size at compile time
int c;
int n = 0;
FILE* inptr = NULL;
inptr = fopen("NMR", "r");
if(inptr == NULL) //We want to check the value of the file we just opened
{ //and plan to use
printf("Error: could not open file\n");
return 1;
}
//We'll keep the original value guards (EOF and '\n') below and add two more
//to make sure we break from the loop
//We use n<98 below to make sure we can always create a null-terminated string,
//If we used 99, the 100th character might be a ')', then we have no room for a
//terminating null-char
for (c = fgetc(inptr); c != ')' && n < 98 && c != EOF && c != '\n'; c = fgetc(inptr))
{
data[n++] = c;
}
if(c != ')') //We hit EOF, \n, or ran out of space in data[]
{
printf("Error: no matching sequence found\n");
return 2;
}
data[n]=')'; //Could also write data[n]=c here, since we know it's a ')'
data[n+1]='\0'; //Add the terminating null character
printf("%s\n",data); //Since it's a properly formatted string, we can use %s
(Note that this example will handle null input characters differently from yours. If you expect null characters to be in the input stream (NMR file) then change the printf("%s",...) line back to the for loop you originally had.
Well with only one example of the format you are trying to parse it's not totally possible to give an answer, however if your input is always like this I would simply have a counter and break after the second comma.
int comma = 0;
for (c = fgetc(inptr); c != EOF && c != '\n' && c != ',' && comma < 1; c = fgetc(inptr))
{
if (data[n] = ',')
comma++;
data[n++] = c;
}
In case the characters inside the parenthesis can be more complex I would simply maintain a boolean state to know if I am actually inside or outside a parenthesis and break when I read a comma outside of it.
Simply read using fgets and store desired string in char * using sscanf-
char *new_data;
new_data=malloc(100); // allocate memory
...
fgets(data,100,inptr); // read from file but check its return
sscanf(data,"%[^)]",new_data); // store string untill ')' in new_data from data
strcat(new_data,")"); // concatenating new_data and ")"
printf("%s",new_data); // print new_data
...
free(new_data); // remember to free memory
Also you should check return of malloc though not done in my example and also close the file opened .

How to read a line from the console in C?

What is the simplest way to read a full line in a C console program
The text entered might have a variable length and we can't make any assumption about its content.
You need dynamic memory management, and use the fgets function to read your line. However, there seems to be no way to see how many characters it read. So you use fgetc:
char * getline(void) {
char * line = malloc(100), * linep = line;
size_t lenmax = 100, len = lenmax;
int c;
if(line == NULL)
return NULL;
for(;;) {
c = fgetc(stdin);
if(c == EOF)
break;
if(--len == 0) {
len = lenmax;
char * linen = realloc(linep, lenmax *= 2);
if(linen == NULL) {
free(linep);
return NULL;
}
line = linen + (line - linep);
linep = linen;
}
if((*line++ = c) == '\n')
break;
}
*line = '\0';
return linep;
}
Note: Never use gets ! It does not do bounds checking and can overflow your buffer
If you are using the GNU C library or another POSIX-compliant library, you can use getline() and pass stdin to it for the file stream.
A very simple but unsafe implementation to read line for static allocation:
char line[1024];
scanf("%[^\n]", line);
A safer implementation, without the possibility of buffer overflow, but with the possibility of not reading the whole line, is:
char line[1024];
scanf("%1023[^\n]", line);
Not the 'difference by one' between the length specified declaring the variable and the length specified in the format string. It is a historical artefact.
So, if you were looking for command arguments, take a look at Tim's answer.
If you just want to read a line from console:
#include <stdio.h>
int main()
{
char string [256];
printf ("Insert your full address: ");
gets (string);
printf ("Your address is: %s\n",string);
return 0;
}
Yes, it is not secure, you can do buffer overrun, it does not check for end of file, it does not support encodings and a lot of other stuff.
Actually I didn't even think whether it did ANY of this stuff.
I agree I kinda screwed up :)
But...when I see a question like "How to read a line from the console in C?", I assume a person needs something simple, like gets() and not 100 lines of code like above.
Actually, I think, if you try to write those 100 lines of code in reality, you would do many more mistakes, than you would have done had you chosen gets ;)
getline runnable example
getline was mentioned on this answer but here is an example.
It is POSIX 7, allocates memory for us, and reuses the allocated buffer on a loop nicely.
Pointer newbs, read this: Why is the first argument of getline a pointer to pointer "char**" instead of "char*"?
main.c
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char *line = NULL;
size_t len = 0;
ssize_t read = 0;
while (1) {
puts("enter a line");
read = getline(&line, &len, stdin);
if (read == -1)
break;
printf("line = %s", line);
printf("line length = %zu\n", read);
puts("");
}
free(line);
return 0;
}
Compile and run:
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out
Outcome: this shows on therminal:
enter a line
Then if you type:
asdf
and press enter, this shows up:
line = asdf
line length = 5
followed by another:
enter a line
Or from a pipe to stdin:
printf 'asdf\nqwer\n' | ./main.out
gives:
enter a line
line = asdf
line length = 5
enter a line
line = qwer
line length = 5
enter a line
Tested on Ubuntu 20.04.
glibc implementation
No POSIX? Maybe you want to look at the glibc 2.23 implementation.
It resolves to getdelim, which is a simple POSIX superset of getline with an arbitrary line terminator.
It doubles the allocated memory whenever increase is needed, and looks thread-safe.
It requires some macro expansion, but you're unlikely to do much better.
You might need to use a character by character (getc()) loop to ensure you have no buffer overflows and don't truncate the input.
As suggested, you can use getchar() to read from the console until an end-of-line or an EOF is returned, building your own buffer. Growing buffer dynamically can occur if you are unable to set a reasonable maximum line size.
You can use also use fgets as a safe way to obtain a line as a C null-terminated string:
#include <stdio.h>
char line[1024]; /* Generously large value for most situations */
char *eof;
line[0] = '\0'; /* Ensure empty line if no input delivered */
line[sizeof(line)-1] = ~'\0'; /* Ensure no false-null at end of buffer */
eof = fgets(line, sizeof(line), stdin);
If you have exhausted the console input or if the operation failed for some reason, eof == NULL is returned and the line buffer might be unchanged (which is why setting the first char to '\0' is handy).
fgets will not overfill line[] and it will ensure that there is a null after the last-accepted character on a successful return.
If end-of-line was reached, the character preceding the terminating '\0' will be a '\n'.
If there is no terminating '\n' before the ending '\0' it may be that there is more data or that the next request will report end-of-file. You'll have to do another fgets to determine which is which. (In this regard, looping with getchar() is easier.)
In the (updated) example code above, if line[sizeof(line)-1] == '\0' after successful fgets, you know that the buffer was filled completely. If that position is proceeded by a '\n' you know you were lucky. Otherwise, there is either more data or an end-of-file up ahead in stdin. (When the buffer is not filled completely, you could still be at an end-of-file and there also might not be a '\n' at the end of the current line. Since you have to scan the string to find and/or eliminate any '\n' before the end of the string (the first '\0' in the buffer), I am inclined to prefer using getchar() in the first place.)
Do what you need to do to deal with there still being more line than the amount you read as the first chunk. The examples of dynamically-growing a buffer can be made to work with either getchar or fgets. There are some tricky edge cases to watch out for (like remembering to have the next input start storing at the position of the '\0' that ended the previous input before the buffer was extended).
How to read a line from the console in C?
Building your own function, is one of the ways that would help you to achieve reading a line from console
I'm using dynamic memory allocation to allocate the required amount of memory required
When we are about to exhaust the allocated memory, we try to double the size of memory
And here I'm using a loop to scan each character of the string one by one using the getchar() function until the user enters '\n' or EOF character
finally we remove any additionally allocated memory before returning the line
//the function to read lines of variable length
char* scan_line(char *line)
{
int ch; // as getchar() returns `int`
long capacity = 0; // capacity of the buffer
long length = 0; // maintains the length of the string
char *temp = NULL; // use additional pointer to perform allocations in order to avoid memory leaks
while ( ((ch = getchar()) != '\n') && (ch != EOF) )
{
if((length + 1) >= capacity)
{
// resetting capacity
if (capacity == 0)
capacity = 2; // some initial fixed length
else
capacity *= 2; // double the size
// try reallocating the memory
if( (temp = realloc(line, capacity * sizeof(char))) == NULL ) //allocating memory
{
printf("ERROR: unsuccessful allocation");
// return line; or you can exit
exit(1);
}
line = temp;
}
line[length] = (char) ch; //type casting `int` to `char`
length++;
}
line[length + 1] = '\0'; //inserting null character at the end
// remove additionally allocated memory
if( (temp = realloc(line, (length + 1) * sizeof(char))) == NULL )
{
printf("ERROR: unsuccessful allocation");
// return line; or you can exit
exit(1);
}
line = temp;
return line;
}
Now you could read a full line this way :
char *line = NULL;
line = scan_line(line);
Here's an example program using the scan_line() function :
#include <stdio.h>
#include <stdlib.h> //for dynamic allocation functions
char* scan_line(char *line)
{
..........
}
int main(void)
{
char *a = NULL;
a = scan_line(a); //function call to scan the line
printf("%s\n",a); //printing the scanned line
free(a); //don't forget to free the malloc'd pointer
}
sample input :
Twinkle Twinkle little star.... in the sky!
sample output :
Twinkle Twinkle little star.... in the sky!
I came across the same problem some time ago, this was my solutuion, hope it helps.
/*
* Initial size of the read buffer
*/
#define DEFAULT_BUFFER 1024
/*
* Standard boolean type definition
*/
typedef enum{ false = 0, true = 1 }bool;
/*
* Flags errors in pointer returning functions
*/
bool has_err = false;
/*
* Reads the next line of text from file and returns it.
* The line must be free()d afterwards.
*
* This function will segfault on binary data.
*/
char *readLine(FILE *file){
char *buffer = NULL;
char *tmp_buf = NULL;
bool line_read = false;
int iteration = 0;
int offset = 0;
if(file == NULL){
fprintf(stderr, "readLine: NULL file pointer passed!\n");
has_err = true;
return NULL;
}
while(!line_read){
if((tmp_buf = malloc(DEFAULT_BUFFER)) == NULL){
fprintf(stderr, "readLine: Unable to allocate temporary buffer!\n");
if(buffer != NULL)
free(buffer);
has_err = true;
return NULL;
}
if(fgets(tmp_buf, DEFAULT_BUFFER, file) == NULL){
free(tmp_buf);
break;
}
if(tmp_buf[strlen(tmp_buf) - 1] == '\n') /* we have an end of line */
line_read = true;
offset = DEFAULT_BUFFER * (iteration + 1);
if((buffer = realloc(buffer, offset)) == NULL){
fprintf(stderr, "readLine: Unable to reallocate buffer!\n");
free(tmp_buf);
has_err = true;
return NULL;
}
offset = DEFAULT_BUFFER * iteration - iteration;
if(memcpy(buffer + offset, tmp_buf, DEFAULT_BUFFER) == NULL){
fprintf(stderr, "readLine: Cannot copy to buffer\n");
free(tmp_buf);
if(buffer != NULL)
free(buffer);
has_err = true;
return NULL;
}
free(tmp_buf);
iteration++;
}
return buffer;
}
There is a simple regex like syntax that can be used inside scanf to take whole line as input
scanf("%[^\n]%*c", str);
^\n tells to take input until newline doesn't get encountered. Then, with %*c, it reads newline character and here used * indicates that this newline character is discarded.
Sample code
#include <stdio.h>
int main()
{
char S[101];
scanf("%[^\n]%*c", S);
printf("%s", S);
return 0;
}
On BSD systems and Android you can also use fgetln:
#include <stdio.h>
char *
fgetln(FILE *stream, size_t *len);
Like so:
size_t line_len;
const char *line = fgetln(stdin, &line_len);
The line is not null terminated and contains \n (or whatever your platform is using) in the end. It becomes invalid after the next I/O operation on stream.
Something like this:
unsigned int getConsoleInput(char **pStrBfr) //pass in pointer to char pointer, returns size of buffer
{
char * strbfr;
int c;
unsigned int i;
i = 0;
strbfr = (char*)malloc(sizeof(char));
if(strbfr==NULL) goto error;
while( (c = getchar()) != '\n' && c != EOF )
{
strbfr[i] = (char)c;
i++;
strbfr = (void*)realloc((void*)strbfr,sizeof(char)*(i+1));
//on realloc error, NULL is returned but original buffer is unchanged
//NOTE: the buffer WILL NOT be NULL terminated since last
//chracter came from console
if(strbfr==NULL) goto error;
}
strbfr[i] = '\0';
*pStrBfr = strbfr; //successfully returns pointer to NULL terminated buffer
return i + 1;
error:
*pStrBfr = strbfr;
return i + 1;
}
The best and simplest way to read a line from a console is using the getchar() function, whereby you will store one character at a time in an array.
{
char message[N]; /* character array for the message, you can always change the character length */
int i = 0; /* loop counter */
printf( "Enter a message: " );
message[i] = getchar(); /* get the first character */
while( message[i] != '\n' ){
message[++i] = getchar(); /* gets the next character */
}
printf( "Entered message is:" );
for( i = 0; i < N; i++ )
printf( "%c", message[i] );
return ( 0 );
}
Here is a minimal implementation to do it, the nice thing is that it will not keep the '\n', however you have to give it a size to read for security:
#include <stdio.h>
#include <errno.h>
int sc_gets(char *buf, int n)
{
int count = 0;
char c;
if (__glibc_unlikely(n <= 0))
return -1;
while (--n && (c = fgetc(stdin)) != '\n')
buf[count++] = c;
buf[count] = '\0';
return (count != 0 || errno != EAGAIN) ? count : -1;
}
Test with:
#define BUFF_SIZE 10
int main (void) {
char buff[BUFF_SIZE];
sc_gets(buff, sizeof(buff));
printf ("%s\n", buff);
return 0;
}
NB: You are limited to INT_MAX to find your line return, which is more than enough.

Resources