Reading multiple lines from input in C - c

I am trying to read multiple lines from console input, but I can't really figure out the way to do it. I made a code that reads only the first line and tried to loop that, but I couldn't figure out the way that works. Any help is welcomed. Thanks in advance. Here is the code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char* readLine() {
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 || c == '\n')
break;
if (--len == 0) {
len = lenmax;
char* linen = realloc(linep, lenmax *= 2);
size_t diff = line - linep;
if (linen == NULL) {
free(linep);
return NULL;
}
line = linen + diff;
linep = linen;
}
*line++ = c;
}
*line = '\0';
return linep;
}
int main() {
for (int i = 0; i < 2; i++) {
printf("%s", readLine());
}
return 0;
}
As you can see, I only managed to loop the function calling twice, which just means I will read only one line twice.
EDIT: I found a way to read code line by line, by doing all the work to the line immediately after its input (saving all I need before the next line is inputted), and tried to stop the while loop while its != '\n', but the loop won't stop, instead it just keeps printing the '\n' character (I keep getting blank lines). Any help on how to fix this?
// Same stuff here
int main() {
char* temp = readLine();
while (*temp != '\n') {
char* temp = readLine();
printf("%s\n", temp);
}
return 0;
}

Related

Replacing strings in C

Okay, guys, I have to write a program that forms a new string based on the given template and the given strings. The template is set as a string where it is necessary to replace all occurrences of the character '%' with a concrete string. If the template contains more characters '%' than the entered strings, characters '%' replaces strings cyclically. If no string is entered, print "ERROR". The number of strings is not known in advance. The end of the entry is indicated by a blank line ("\n").
Also, there are some conditions I need to fulfill, which are:
1) Implement char * readLine () function; which reads one row from the standard input and returns the pointer to that loaded row.
2) Implement char ** readLines (int * n) function; which reads strings that change all occurrences of the character '%' in the template. The function returns an array of pointers to the strings entered as a return value. Also, the function returns the number of values entered via argument n.
3) Implement char * format function (char * format, char ** values, int n); which formats the string format by changing each occurrence of the '%' character to a corresponding string from a string of values of length n.
4) Write a master program that, using previously implemented functions, reads the template and strings from the standard input, forms a new string as described, and prints the result to standard output.
I barely understand what I'm supposed to do so I came here to ask for help. What I did for now is the first task, but on the output I get 1 more blank line than I'm supposed to and I can't find any way to fix it. Any kind of help is welcomed since I'm really stuck here, even explaining what I'm supposed to do in some tasks, or making current code simpler is awesome. Thanks in advance. Here is my code.
EDIT: Added examples.
Input:
% be or not % be.
To
Output:
To be or not To be.
Input:
% and % make purple.
Blue
red
Output:
Blue and red make purple.
#include<stdio.h>
#include<stdlib.h>
char* readLine() {
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;
}
int main() {
printf("%s", readLine());
return 0;
}
EDIT: For the 2nd task, I tried to do something similar like in the first, but I couldn't really figure out how to make it so that it works. Here is what I did:
char** readLines(int* n) {
char* line = malloc(100), * linep = line;
size_t lenmax = 100, len = lenmax;
int c, flag = 0;
if (line == NULL && flag > 1) {
char* linen = realloc(linep, lenmax *= 2);
}
else if (line == NULL && flag == 0)
return NULL;
for (;;) {
c = fgetc(stdin);
if (c == EOF || c == '\n')
break;
if (--len == 0) {
len = lenmax;
char* linen = realloc(linep, lenmax *= 2);
size_t diff = line - linep;
if (linen == NULL) {
free(linep);
return NULL;
}
line = linen + diff;
linep = linen;
flag++;
}
*line++ = c;
}
*line = '\0';
char* temp = linep;
return linep;
}
At least this problem
line = linen + (line - linep); is UB, as code cannot use linep after it has been free'd in realloc().
Instead calculate and save the line - linep difference before realloc()
size_t diff = line - linep; // add
char* linen = realloc(linep, lenmax *= 2);
if (linen == NULL) {
...;
}
// line = linen + (line - linep);
line = linen + diff;
OP apparently does not want to retain the '\n'. Change
// if ((*line++ = c) == '\n') break;
if (c == '\n') break;
*line++ = c;
I'd also recommend a right size realloc() step in the end.
If you want to read a line until EOF or '\n', but without the newline in your string, you need to do this:
for (;;) {
c = fgetc(stdin);
if (c == EOF)
break;
// realloc logic comes here
if (c == '\n')
break;
*line++ = c;
}

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.

Can't stop reading Unicode file with !feof()

I don't know why while loop can't stop. It can't compare c with Delim neither stop by reaching eof.
wchar_t* Getline(const wchar_t* Filename, const wchar_t Delim){
FILE* f = _wfopen(Filename, L"r, ccs=UTF-8");
wchar_t* info = NULL;
wchar_t* temp = NULL;
int count = 1;
int i = 0;
wchar_t c;
c = fgetwc(f);
while (c != Delim || !feof(f))
{
count++;
temp = (wchar_t*)realloc(info, count * sizeof(wchar_t));
if (temp)
{
info = temp;
info[i] = c;
i++;
}
else
{
free(info);
wprintf(L"Failed to read\n");
}
c = fgetwc(f);
}
info[i] = '\0';
fclose(f);
return info;
}
After reading all character in file. It seem not to stop. Even c are the same with Delim. And !feof(f) hasn't worked too. I have try c != WEOF but fail too
I thought that the problem is in the file that I read but not. I have change another file but the same problem.
Thanks for helping me!
You wish to loop whilst you have not got a Delim character and it is not the end of the file, so replace the || with &&
while (!feof(f) && c != Delim)
Edit: the order has also been changed in response to comments

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 :)

fgetc read file line by line

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);
}

Resources