fgetc read file line by line - c

So I'm working on a function that will use fgetc to read a line into a buffer. so I can use that buffer as I please, and then refill the buffer with the next line. My function works however I have to repeat code outside of the for loop to process the last line as shown here:
for(i = 0, c = 1; ch != EOF; i++)
{
ch = fgetc(grab);
if(ch == 0x0A)
{
/*Process Line*/
c = 1;
}
else
{
linetmp = realloc(line, (c + 1) * sizeof(char));
if(!linetmp)
{
free(line);
free(url);
printf("\nError! Memory allocation failed!");
return 1;
}
line = linetmp;
line[c - 1] = ch;
line[c] = 0x00;
c++;
}
}
/*repeat if(ch == 0x0A) statement*/
I would rather do this all in the same loop but am not sure on how I would go about doing this. Any help would be greatly appreciated!

I would recommend that you instead use getline() if you're on a POSIX system.
Also, your logic is strange since you check for EOF in the loop header only, but update ch inside the loop. That means it will run through with ch == EOF, before the loop condition is re-evaluated.
You should try putting the updating and the check together, making the loop header read like this:
for(i = 0, c = 1; (ch = fgetc()) != EOF; i++)
Also, you need to think about line separators, both '\n' (carriage return) and '\n' (line feed) can occur.

I don't think you should reallocate after each character. If you want to have the buffer at the smallest value needed, you could reallocate at the end with ( strlen() + 1); Also, there is a function fgets() which reads a line.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int somefunc(FILE *grab)
{
int current_size = 100;
int data_size = current_size - 1;
char *url = malloc(current_size);
char *line = malloc(current_size);
char *linetmp;
int ch;
ch = fgetc(grab);
int i = 0;
int c = 0;
while (ch != EOF && ch != 0x0A )
{
i++;
if ( i > data_size )
{
current_size = current_size * 2;
data_size = current_size - 1;
linetmp = realloc(line, current_size);
if (!linetmp)
{
free(line);
free(url);
printf("\nError! Memory allocation failed!");
return 1;
}
line = linetmp;
}
line[c] = ch;
c++;
ch = fgetc(grab);
}
line[c] = '\0';
linetmp = realloc(line,strlen(line) + 1);
line = linetmp;
printf("we just read line->%s\n",line);
free(line);
free(url);
return 0;
}
int main(void)
{
char *cpFilename = "somefile.txt";
FILE *fp = fopen(cpFilename,"r");
if ( fp == NULL )
{
printf("ERROR: could not open %s\n",cpFilename);
printf("Error code: %d\n",errno);
perror("ERROR:");
return 1;
}
int return_code = somefunc(fp);
while (return_code != EOF && return_code != 1)
{
return_code = somefunc(fp);
}
fclose(fp);
}

Related

Reading Multiple lines in C

So I am trying to read input from a text file and print the exact same thing I read in C.So this below is the input followed by enter:
input: Hi
output: Hi
#include <stdio.h>
#include <stdlib.h>
char *inputString(FILE *fp, size_t size) {
//The size is extended by the input with the value of the provisional
char *str;
int ch;
size_t len = 0;
str = realloc(NULL, sizeof(char) * size); //size is start size
if (!str)
return str;
while (EOF != (ch = fgetc(fp)) && ch != '\n') {
str[len++] = ch;
if (len == size) {
str = realloc(str, sizeof(char) * (size += 16));
if (!str)
return str;
}
}
str[len++] = '\0';
return realloc(str, sizeof(char) * len);
}
int main(void) {
char *m;
// printf("input string : ");
m = inputString(stdin, 10);
printf("%s\n", m);
free(m);
return 0;
}
For this input:
Hi, this is the first line
This is the second line
This is the third line \n
This is the output I expected:
Hi, this is the first line
This is the second line
This is the third line \n
This is what I got:
Hi, this is the first line
It makes sense that the code is printing only the first line, but since the condition in the guard will no longer be true after hitting the new line, but I don't know how to structure my code so it reads line by line and prints them respectively.
If you want the code to read each line, remove && ch != '\n' from the condition of the while loop.
Also, the code is reading from stdin instead of a file. Use fopen to read from a file, i.e. m = inputString(fopen("filename.txt", "r"), 512).
Try this,
#include<stdio.h>
void main(int argc, char **argv)
{
int cnt=0;
char buf[1024];
FILE *fptr=stdin;
printf("Input: \n");
char ch=fgetc(fptr);
buf[cnt++]=ch;
while(ch!='$')
{
buf[cnt++]=ch;
ch=fgetc(fptr);
}
buf[cnt++]='$';
buf[cnt]='\0';
printf("Output:\n");
fputs(buf,stdout);
fclose(fptr);
}
I have put '$' as the delimiter.
I have used an extra buffer as newline is bound to EOF for stdin. So if I print out the character immediately it comes out of loop.
All you need is repeat the process as long as you can read lines:
int main(void) {
char *m;
// printf("input strings: ");
while ((m = inputString(stdin, 10)) != NULL) {
printf("%s\n", m);
free(m);
}
return 0;
}
For this to work correctly, you must return NULL at end of file:
#include <stdio.h>
#include <stdlib.h>
char *inputString(FILE *fp, size_t size) {
//The size is extended by the input with the value of the provisional
int ch;
size_t len = 0;
char *str = malloc(size);
if (str == NULL)
return NULL;
while ((ch = fgetc(fp)) != EOF && c != '\n') {
if (len + 2 > size) {
char *new_str = realloc(str, size += 16);
if (!new_str) {
free(str);
return NULL;
str = new_str;
}
str[len++] = ch;
}
if (c == EOF && len == 0) {
/* at end of file */
free(str);
return NULL;
}
str[len++] = '\0';
return realloc(str, len);
}
Instead of:
while(EOF!=(ch=fgetc(fp))&& ch != '\n' ){
// stuff
}
you could do:
while(EOF!=(ch=fgetc(fp))){
// stuff
if (ch == '\n') break;
}
Now you have consumed the newline.

problems with pointers to copy characters

I have problems with getstring. I do not know why it does not work, the output in the main function printf do not put nothing
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *getstring(unsigned int len_max)
{
char *linePtr = malloc(len_max + 1); // Reserve storage for "worst case."
if (linePtr == NULL) { return NULL; }
int c = 0;
unsigned int i = 0;
while (i < len_max && (c = getchar()) != '\n' && c != EOF){
*linePtr++ = (char)c;
i++;
}
*linePtr = '\0';
return linePtr;
}
int main()
{
char *line = getstring(10);
printf("%s", line);
free(line);
return 0;
}
The problem is that linePtr points to the end of the string containing the input line, not the beginning, because you do linePtr++ during the loop.
Instead of incrementing linePtr, use linePtr[i++] to store each character during the loop.
char *getstring(unsigned int len_max)
{
char *linePtr = malloc(len_max + 1); // Reserve storage for "worst case."
if (linePtr == NULL) { return NULL; }
int c = 0;
unsigned int i = 0;
while (i < len_max && (c = getchar()) != '\n' && c != EOF){
linePtr[i++] = (char)c;
}
linePtr[i] = '\0';
return linePtr;
}
If you really need to do it by incrementing a pointer, you need to save the original value of linePtr in another variable, and return that rather than the one that you increment.
your problem is that you are returning the end of your buffer, You need to keep a copy of linePtr or to index it. (You are incrementing it in your loop);

can anyone explain me how does this function work?

I don't understand what this function do. Can anyone explain me in detail please?
char *my_getline(FILE *stream) {
char *line = NULL;
size_t pos = 0;
int c;
while ((c = getc(stream)) != EOF) {
char *newp = realloc(line, pos + 2);
if (newp == NULL) {
free(line);
return NULL;
}
line = newp;
if (c == '\n')
break;
line[pos++] = (char)c;
}
if (line) {
line[pos] = '\0';
}
return line;
}
If you can add a comment on my code, I think that will help me. I want to search a substring in a string and I found this function code.
This is the main function:
int main(void) {
char *str, *sub;
size_t len1, len2, i, count = 0;
printf("Insert string :\n");
str = my_getline(stdin);
printf("insert substring :\n");
sub = my_getline(stdin);
if (str && sub) {
len1 = strlen(str);
len2 = strlen(sub);
for (i = 0; i + len2 <= len1; i++) {
if (!memcmp(str + i, sub, len2)) {
count++;
printf("Substring found at index : %d\n", i);
}
}
printf("in the number of: %d\n", count);
if (count == 0) {
printf("Substring not found\n");
}
}
free(str);
free(sub);
return 0;
}
I understand the main function but unable to understand the logic in function my_getline.
Please help me in understanding the logic. Thanks!
char *my_getline(FILE *stream) {
// pointer to the line to be read:
char *line = NULL;
// position of the next character:
size_t pos = 0;
// single character:
int c;
while ((c = getc(stream)) != EOF) { // read 1 character at a time until EOF
// allocate a new buffer with room for the char just read + a 0 terminator
// when `line` is NULL, this is the same as `malloc()`, otherwise it
// will change the size of the allocation:
char *newp = realloc(line, pos + 2);
// check for errors:
if (newp == NULL) {
free(line);
return NULL;
}
// no errors, assign new buffer to `line`:
line = newp;
// end of line found: we're done:
if (c == '\n')
break;
// otherwise add new character to the line:
line[pos++] = (char)c;
}
// if there was *anything* to read, add 0 terminator (marks end of string):
if (line) {
line[pos] = '\0';
}
return line;
}
That's about it. Note it's horribly inefficient for two reasons: It reads only one character at a time and it calls realloc() for each and every character.
A better solution would use e.g. fgets() and increase the buffer size in reasonable chunks, for example like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define GETLINE_CHUNK 1024
static void xrealloc(void *bufPtr, size_t size)
{
void **buf = bufPtr;
void *tmp = realloc(*buf, size);
if (!tmp)
{
free(*buf);
*buf = 0;
}
*buf = tmp;
}
char *my_getline(FILE *stream)
{
// allocate first chunk:
char *buf = malloc(GETLINE_CHUNK);
if (!buf) return 0;
*buf = 0;
size_t pos = 0;
// read up to GETLINE_CHUNK bytes, until newline:
while (fgets(buf + pos, GETLINE_CHUNK, stream))
{
// look for newline:
char *nlPos = strchr(buf, '\n');
if (nlPos)
{
// found, then our line is complete
*nlPos = 0;
// shrink buffer to needed size
xrealloc(&buf, nlPos-buf+1);
return buf;
}
// set next offset to read
pos = strlen(buf);
// increase buffer size to have room for a whole other GETLINE_CHUNK:
xrealloc(&buf, pos + GETLINE_CHUNK);
if (!buf) return 0;
}
// if nothing was read, free buffer and return NULL:
if (*buf == 0)
{
free(buf);
buf = 0;
}
return buf;
}
int main(void)
{
char *line = my_getline(stdin);
if (line)
{
puts(line);
free(line);
}
else puts("no input!");
return 0;
}
Well this function gives you line, Lets go Step by Step:
char *my_getline(FILE *stream) {
char *line = NULL; //this is just pointer initialization
size_t pos = 0; //position variable definition and init
int c; //a variable to store temporary character
while ((c = getc(stream)) != EOF) //read every character till end of file
{
// To dynamically allocate memory, with reference to the
// number of character and plus '2' is just to compensate null
// character and the character(Since pos is 0)
char *newp = realloc(line, pos + 2);
if (newp == NULL) { // this is to check whether memory was alloacted properly or not.
free(line); //if not free line
return NULL;// break the program and return NULL
}
line = newp;// if memory is allocated properly store allocated memory in line pointer
if (c == '\n') //if new line is detected
break;// break the while loop
line[pos++] = (char)c; // store the character in dynamically allocated memory and new character in new location.
}
if (line) { //if line contains something then add a null character at last, to complete that string
line[pos] = '\0';
}
return line; //returns the content of line.
}
Hope this helps :)

How to count the number of characters entered in a char array in C

I have a function that reads in a line from stdin and then returns the number of characters that the user inputted. The problem is that I can't seem to figure out how to count the number of characters. Here is the code:
int inputline(char* buf, size_t bufSize)
{
static int numRead = 0;
int ch = 0;
//static int totalChars = 0;
while (numRead < bufSize - 1 && ch != '\n') {
ch = getchar();
if(ch == EOF){
if(feof(stdin)){
ch = '\n'; //treated as if the user hit return and ends loop
puts("EOF");
}else{
numRead = -1;
break; //ends loop
}
}else{
buf[numRead] = ch;
++numRead;
}
if (ch == '\n') {
buf[numRead-1] = 0; // replace newline with null terminator
} else {
buf[bufSize-1] = 0; // ensure buffer is properly null terminated
}
while (ch != '\n') {
ch = getchar();
}
return sizeof(buf);
}
}
I had thought numRead would count this but it doesn't and I'm not entirely sure why. Any help is really appreciated!
You are making your function a lot more complex than it needs to be. Here's a simplified version:
int inputline(char* buf, size_t bufSize)
{
// Why did you have it static. It makes sense to be automatic.
int numRead = 0;
int ch = 0;
// The logic to check for when to stop is much simpler
while ( numRead < bufSize && ((ch = getchar()) != EOF && ch != '\n') )
{
buf[numRead] = ch;
++numRead;
}
// Always null terminate the buffer.
buf[numRead] = '\0';
// You know how many characters were stored in buf.
// Return it.
return numRead;
}

What's wrong with strtol?

I have this code, which should run fine, but for some reason, the loop would cycle through when I free the string before the conditional check of the loop. And the only way to get out from the loop is by giving integer with more than 3 digits (input > 99 || input < -99).
I'm using gcc to compile this code with code::blocks as IDE.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* createString(void);
int main() {
int temp = 0;
char* string = 0;
char* error = 0;
do {
printf("\n Integer: ");
string = createString();
temp = strtol(string, &error, 10);
if (*error != '\n' && *error != '\0') printf("\n Input is not an integer");
free(string);
string = 0;
} while (*error != '\n' && *error != '\0');
free(error);
error = 0;
return 0;
}
char* createString() {
char* string = 0;
size_t size = 0;
size_t index = 0;
int ch = EOF;
do {
ch = getc(stdin);
if (ch == EOF || ch == '\n') ch = 0;
if (size <= index) string = (char*) realloc(string, size += 5);
if (!string) {
perror("realloc");
exit(EXIT_FAILURE);
}
string[index++] = ch;
} while(ch);
return string;
}
I did a work-around it by moving the free-ing process to the beginning of the loop cycle and after the loop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* createString(void);
int main() {
int temp = 0;
char* string = 0;
char* error = 0;
do {
free(string);
string = 0;
printf("\n Integer: ");
string = createString();
temp = strtol(string, &error, 10);
if (*error != '\n' && *error != '\0') printf("\n Input is not an integer");
} while (*error != '\n' && *error != '\0');
free(string);
string = 0;
free(error);
error = 0;
return 0;
}
char* createString() {
char* string = 0;
size_t size = 0;
size_t index = 0;
int ch = EOF;
do {
ch = getc(stdin);
if (ch == EOF || ch == '\n') ch = 0;
if (size <= index) string = (char*) realloc(string, size += 5);
if (!string) {
perror("realloc");
exit(EXIT_FAILURE);
}
string[index++] = ch;
} while(ch);
return string;
}
The code works fine now, but I'm wondering what is strtol doing.
free(error);
Remove it. error is not allocated in strtol or anywhere else. It is a pointer that points to the middle of string. Freeing it is UB.
You say:
for some reason, the loop would cycle through when I free the string before the conditional check of the loop
Keep in mind that with the call strtol(string, &error, 10); the pointer error will point into the string string. So if you free string before doing this:
if (*error != '\n' && *error != '\0') printf("\n Input is not an integer");
or this:
while (*error != '\n' && *error != '\0')
You'll invoke undefined behavior because error will be pointing to freed memory.

Resources