Infinite Loop on Get_Next_Line in C - c

I have to create a C function that returns a line read from a file descriptor. I have to define a macro READ_SIZE (that can be editable). This READ_SIZE indicates the number of characters to read at each call of read(). The number can only be positive.
I also have to use one or several static variables to save the characters that were read but not sent back to the calling function. One .C file (5 functions max, 25 lines max per function) and one .h file only.
My function Get_Next_Line shall return its return without the '\n'. If there is nothing more to read on the file descriptor, or if an error occur while reading, the function returns NULL.
Here is the prototype of the function:
char *get_next_line(const int fd)
FUNCTIONS ALLOWED: malloc, free, read, write (to use with my_putchar, my_putstr, etc).
Here is what I have, but it doesn't work. It does an infinite loop I am trying to know why.
char *my_strcat(char *str1, char *str2)
{
int i;
int j;
int s;
char *strfinal;
i = 0;
j = 0;
s = 0;
if ((strfinal = malloc(sizeof(char) * (my_strlen(str1) + my_strlen(str2)
+ 1))) == NULL)
return (NULL);
while (str1[i] != '\0')
{
strfinal[j] = str1[i];
i++;
j++;
}
while (str2[s] != '\0')
{
strfinal[j] = str2[s];
s++;
j++;
}
free(str1);
strfinal[j] = '\0';
return (strfinal);
}
char *get_next_line(const int fd)
{
int n;
int i;
char *str_to_return;
static char buff[READ_SIZE] = {'\0'};
n = 1;
i = 0;
str_to_return = NULL;
while (n)
{
if (i == 0 && buff == '\0')
{
if ((read(fd, buff, READ_SIZE)) <= 0)
return(str_to_return);
if (i == READ_SIZE - 1 || buff[i] == '\n')
{
n = 0;
str_to_return = my_strcat(buff, str_to_return);
i = -1;
}
}
i++;
}
printf("%s\n", str_to_return);
return (str_to_return);
}

in this code:
while (str1[i] != '\0')
{
strfinal[j] = str1[i];
i++;
j++;
}
what guarantee do you have that there will be the null character \0 somewhere in str1[] ???
same goes for the str2 while loop.
If no null character is encountered, then there will be an infinite loop there.
verify the functions you are using to populate characters into memory under str1[] and str2[] include the null character. Since you are only using the read() function prior then that answer is no.
The problem with your two while loops for str1[] and str2[] is that you are relying on the null character to already be there in memory. And that then begs the question, who put that data there in memory and were they given a requirement to terminate the character data with a null character?
you therefore need to somehow place a control over any loop you write so as not get caught in an infinite loop condition; in this case maybe use a counter and after so many advances of the i to access str1[i] then stop, because you have yet to see a null character.
for example, the fgets() function will read so many characters from a FILE stream into an array, and always terminate it with the null character.

if (i == 0 && buff == '\0')
is always false because your definition of buff is
static char buff[READ_SIZE] = {'\0'};
You are attempting to test if buff is empty when i is 0. However as a char pointer, buff is an address and is never 0. You mean to make the if
if (i == 0 && buff[0] == '\0')
in order to check if the first character is the Null character.
However, once i is incremented, then it always fails even if you test against
if (i == 0 && buff[i] == '\0')
in order to find the NULL character within the buffer. Since you enter the while with i = 0 and are checking if buff is empty, you do not need the while.
If you want to just fill the buffer and keep reading until it is full, you need a different type of test. You also need a way of checking if you need to exit the while loop if the if fails (put in an else to determine what to do).
You also do not need to check each character in buff against '\0' because your code has always insured that it ends with one (even for initialization). Thus, strlen(buff) would be valid.
Another point is that when you call mystrcat() you have already verified that buffer is empty.
Also, since the second string in the call is what you read in, then the mystrcat() will not always have a '\0' at the end of str2 (though you are guaranteeing that buff (str1) will). You should call it with the number of characters in str2 to use.

Related

how to stop my program from skipping characters before saving them

I am making a simple program to read from a file character by character, puts them into tmp and then puts tmp in input[i]. However, the program saves a character in tmp and then saves the next character in input[i]. How do I make it not skip that first character?
I've tried to read into input[i] right away but then I wasn't able to check for EOF flag.
FILE * file = fopen("input.txt", "r");
char tmp;
char input[5];
tmp= getc(file);
input[0]= tmp;
int i=0;
while((tmp != ' ') && (tmp != '\n') && (tmp != EOF)){
tmp= getc(file);
input[i]=tmp;
length++;
i++;
}
printf("%s",input);
It's supposed to print "ADD $02", but instead it prints "DD 02".
You are doing things in the wrong order in your code: The way your code is structures, reading and storing the first char is moved out of the loop. In the loop, that char is then overwritten. In that case start with i = 1.
Perhaps you want to read the first character anyway, but I guess you want to read everything up to the first space, which might be the first character. Then do this:
#include <stdio.h>
int main(void)
{
char input[80];
int i = 0;
int c = getchar();
while (c != ' ' && c != '\n' && c != EOF) {
if (i + 1 < sizeof(input)) { // store char if the is room
input[i++] = c;
}
c = getchar();
}
input[i] = '\0'; // null-terminate input
puts(input);
return 0;
}
Things to note:
The first character is read before the loop. the loop condition and the code that stores the char then use that char. Just before the end of the loop body, the next char is read, which will then be processed in the next iteration.
You don't enforce that the char buffer input cannot be overwritten. This is dangerous, especially since your buffer is tiny.
When you construct strings char by char, you should null-terminate it by placing an explicit '\0' at the end. You have to make sure that there is space for that terminator. Nearly all system functions like puts or printf("%s", ...) expect the string to be null-terminated.
Make the result of getchar an int, so that you can distinguish between all valid character codes and the special value EOF.
The code above is useful if the first and subsequent calls to get the next item are different, for example when tokenizing a string with strtok. Here, you can also choose another approach:
while (1) { // "infinite loop"
int c = getchar(); // read a char first thing in a loop
if (c == ' ' || c == '\n' || c == EOF) break;
// explicit break when done
if (i + 1 < sizeof(input)) {
input[i++] = c;
}
}
This approach has the logic of processing the chars in the loop body only, but you must wrap it in an infinite loop and then use the explicit break.

puts() output is appended "time" string

I get very unexpected output from quite simple code
char ch = getchar(), word[100], *p = word;
while (ch != '\n') {
*(p++) = ch;
ch = getchar();
}
puts(word);
output of any 17 character input is appended by "time" like
12345678901234567time
if exceeds "time" is overwritten like
1234567890123456789me
Am I doing something wrong?
puts expects a pointer to string. And a string needs to have a terminating null character - \0 - to signify where the string ends.
But in your case, you did not write the \0 at the end to signify that the string ends there.
You need to do:
char ch = getchar(), word[100], *p = word;
/* Also check that you are not writing more than 100 chars */
int i = 1;
while(ch != '\n' && i++ < 100){
*(p++) = ch;
ch = getchar();
}
*p = '\0'; /* write the terminaring null character */
puts(word);
Before, when you were not writing the terminating null character you could not expect anything determinate to print. It could also have been 12345678901234567AnyOtherWord or something.
There are multiple issues in your code:
You do not null terminate the string you pass to puts(), invoking undefined behavior... in your case, whatever characters happen to be present in word after the last one read from stdin are printed after these and until (hopefully) a '\0' byte is finally found in memory.
You read a byte from stdin into a char variable: this does not allow you to check for EOF, and indeed you do not.
If you read a long line, you will write bytes beyond the end if the word array, invoking undefined behavior. If the end of file is encountered before a '\n' is read from stdin, you will definitely write beyond the end of the buffer... Try for example giving an empty file as input for your program.
Here is a corrected version:
char word[100];
char *p = word;
int ch;
while ((ch = getchar()) != EOF && ch != '\n') {
/* check for long line: in this case, we truncate the line */
if (p < word + sizeof(word) - 1) {
*p++ = ch;
}
}
*p = '\0';
puts(word);

Return a string made with a line read from input

i am trying to code a C function which returns a line read from the input as a char* . I am on Windows and i test my program in the command line by giving files as input and output of my program like this:
cl program.c
program < test_in.txt > test_out.txt
This is my (not working) function:
char* getLine(void)
{
char* result = "";
int i, c;
i = 1;
while((c = getchar()) != EOF)
{
*result++ = c;
i++;
if(c == '\n')
return result - i;
}
return result - i;
}
I was expecting it to work because i previously wrote:
char* getString(char* string)
{
//char* result = string; // the following code achieve this.
char* result = "";
int i;
for(i = 1; *result++ = *string++; i++);
return result - i;
}
And these lines of code have a correct behaviour.
Even if every answers will be appreciated, i would be really thankfull
if any of you could explain me why my getString() function works while my getLine() function doesn't.
Your function does not allocate enough space for the string being read. The variable char* result = "" defines a char pointer to a string literal ("", empty string), and you store some arbitrary number of characters into the location pointed to by result.
char* getLine(void)
{
char* result = ""; //you need space to store input
int i, c;
i = 1;
while((c = getchar()) != EOF)
{
*result++ = c; //you should check space
i++;
if(c == '\n')
return result - i; //you should null-terminate
}
return result - i; //you should null-terminate
}
You need to allocate space for your string, which is challenging because you don't know how much space you are going to need a priori. So you need to decide whether to limit how much you read (ala fgets), or dynamically reallocate space as you read more. Also, how to you indicate that you have finished input (reached EOF)?
The following alternative assumes dynamic reallocation is your chosen strategy.
char* getLine(void)
{
int ch; int size=100; size_t pos=0;
char* result = malloc(size*sizeof(char*));
while( (ch=getchar()) != EOF )
{
*result++ = ch;
if( ++pos >= size ) {
realloc(result,size+=100);
//or,realloc(result,size*=2);
if(!result) exit(1); //realloc failed
}
if( c=='\n' ) break;
}
*result = '\0'; //null-terminate
return result - pos;
}
When you are done with the string returned from the above function, please remember to free() the allocated space.
This alternative assumes you provide a buffer to store the string (and specifies the size of the buffer).
char* getLine(char* buffer, size_t size)
{
int ch;
char* result = buffer;
size_t pos=0;
while( (ch=getchar()) != EOF )
{
*result++ = ch;
if( ++pos >= size ) break; //full
if( c=='\n' ) break;
}
*result = '\0'; //null-terminate
return buffer;
}
Both avoid the subtle interaction between detecting EOF, and having enough space to store a character read. The solution is to buffer a character if you read and there is not enough room, and then inject that on a subsequent read. You will also need to null-ter
Both functions have undefined behaviour since you are modifying string literals. It just seems to work in one case. Basically, result needs to point to memory that can be legally accessed, which is not the case in either of the snippets.
On the same subject, you might find this useful: What Every C Programmer Should Know About Undefined Behavior.
Think of it this way.
When you say
char* result = "";
you are setting up a pointer 'result' to point to a 1-byte null terminated string (just the null). Since it is a local variable it will be allocated on the stack.
Then when you say
*result++ = c;
you are storing that value 'c' in to that address + 1.
So, where are you putting it?
Well, most stacks are to-down; so they grow toward lower addresses; so, you are probably writing over what is already on the stack (the return address for whatever called this, all the registers it needs restore and all sorts of important stuff).
That is why you have to be very careful with pointers.
When you expect to return a string from a function, you have two options (1) provide a string to the function with adequate space to hold the string (including the null-terminating character), or (2) dynamically allocate memory for the string within the function and return a pointer. Within your function you must also have a way to insure your are not writing beyond the end of the space available and you are leaving room for the null-terminating character. That requires passing a maximum size if you are providing the array to the function, and keeping count of the characters read.
Putting that together, you could do something similar to:
#include <stdio.h>
#define MAXC 256
char* getLine (char *s, int max)
{
int i = 0, c = 0;
char *p = s;
while (i + 1 < max && (c = getchar()) != '\n' && c != EOF) {
*p++ = c;
i++;
}
*p = 0;
return s;
}
int main (void) {
char buf[MAXC] = {0};
printf ("\ninput : ");
getLine (buf, MAXC);
printf ("output: %s\n\n", buf);
return 0;
}
Example/Output
$ ./bin/getLine
input : A quick brown fox jumps over the lazy dog.
output: A quick brown fox jumps over the lazy dog.

Dynamically created C string

I'm trying to get an expression from the user and put it in a dynamically created string. Here's the code:
char *get_exp() {
char *exp, *tmp = NULL;
size_t size = 0;
char c;
scanf("%c", &c);
while (c != EOF && c != '\n') {
tmp = realloc(exp, ++size * sizeof char);
if (tmp == NULL)
return NULL;
exp = tmp;
exp[size-1] = c;
scanf("%c", &c);
}
tmp = realloc(exp, size+1 * sizeof char);
size++;
exp = tmp;
exp[size] = '\0';
return exp;
}
However, the first character read is a newline char every time for some reason, so the while loop exits. I'm using XCode, may that be the cause of the problem?
No, XCode is not part of your problem (it is a poor workman who blames his tools).
You've not initialized exp, which is going to cause problems.
Your code to detect EOF is completely broken; you must test the return value of scanf() to detect EOF. You'd do better using getchar() with int c:
int c;
while ((c = getchar()) != EOF && c != '\n')
{
...
}
If you feel you must use scanf(), then you need to test each call to scanf():
char c;
while (scanf("%c", &c) == 1 && c != EOF)
{
...
}
You do check the result of realloc() in the loop; that's good. You don't check the result of realloc() after the loop (and you aren't shrinking your allocation); please check every time.
You should consider using a mechanism that allocates many bytes at a time, rather than one realloc() per character read; that is expensive.
Of course, if the goal is simply to read a line, then it would be simplest to use POSIX getline(), which handles all the allocation for you. Alternatively, you can use
fgets() to read the line. You might use a fixed buffer to collect the data, and then copy that to an appropriately sized dynamically allocated buffer. You would also allow for the possibility that the line is very long, so you'd check that you'd actually got the newline.
Here on Windows XP/cc, like Michael said, it works if exp is initialized to NULL.
Here's a fixed code, with comments explaining what is different from your code in the question:
char *get_exp()
{
// keep variables with narrowest scope possible
char *exp = NULL;
size_t size = 0;
// use a "forever" loop with break in the middle, to avoid code duplication
for(;;) {
// removed sizeof char, because that is defined to be 1 in C standard
char *tmp = realloc(exp, ++size);
if (tmp == NULL) {
// in your code, you did not free already reserved memory here
free(exp); // free(NULL) is allowed (does nothing)
return NULL;
}
exp = tmp;
// Using getchar instead of scanf to get EOF,
// type int required to have both all byte values, and EOF value.
// If you do use scanf, you should also check it's return value (read doc).
int ch = getchar();
if (ch == EOF) break; // eof (or error, use feof(stdin)/ferror(stdin) to check)
if (ch == '\n') break; // end of line
exp[size - 1] = ch; // implicit cast to char
}
if (exp) {
// If we got here, for loop above did break after reallocing buffer,
// but before storing anything to the new byte.
// Your code put the terminating '\0' to 1 byte beyond end of allocation.
exp[size-1] = '\0';
}
// else exp = strdup(""); // uncomment if you want to return empty string for empty line
return exp;
}

Strcat throws segmentation fault on simple getch-like password input

I am using Linux and there is a custom function of which returns an ASCII int of current key sort of like getch(). When trying to get used to it and how to store the password I came into an issue, my code is as follows:
int main() {
int c;
char pass[20] = "";
printf("Enter password: ");
while(c != (int)'\n') {
c = mygetch();
strcat(pass, (char)c);
printf("*");
}
printf("\nPass: %s\n", pass);
return 0;
}
Unfortunately I get the warning from GCC:
pass.c:26: warning: passing argument 2 of ‘strcat’ makes pointer from integer without a cast
/usr/include/string.h:136: note: expected ‘const char * __restrict__’ but argument is of type ‘char’
I tried using pointers instead of a char array for pass, but the second I type a letter it segfaults. The function works on its own but not in the loop, atleast not like getch() would on a Windows system.
What can you see is wrong with my example? I am enjoying learning this.
EDIT: Thanks to the answers I came up with the following silly code:
int c;
int i = 0;
char pass[PASS_SIZE] = "";
printf("Enter password: ");
while(c != LINEFEED && strlen(pass) != (PASS_SIZE - 1)) {
c = mygetch();
if(c == BACKSPACE) {
//ensure cannot backspace past prompt
if(i != 0) {
//simulate backspace by replacing with space
printf("\b \b");
//get rid of last character
pass[i-1] = 0; i--;
}
} else {
//passed a character
pass[i] = (char)c; i++;
printf("*");
}
}
pass[i] = '\0';
printf("\nPass: %s\n", pass);
The problem is that strcat expects a char * as its second argument (it concatenates two strings). You don't have two strings, you have one string and one char.
If you want to add c to the end of pass, just keep an int i that stores the current size of pass and then do something like
pass[i] = (char) c.
Make sure to null-terminate pass when you are done (by setting the last position to 0).
A single character is not the same as a string containing a single character.
In other words, 'a' and "a" are very different things.
A string, in C, is a null-terminated array of chars. Your "pass" is an array of 20 chars - a block of memory containing space for 20 chars.
The function mygetch() returns a char.
What you need to do is to insert c into one of the spaces.
Instead of "strcat(pass, c)", you want to do "pass[i] = c", where i starts at zero, and increments by one for every time you call mygetch().
Then you need to do a pass[i] = '\0', when the loop is done, with i equal to the number of times you called mygetch(), to add the null terminator.
You're other problem is that you haven't set a value for c, the first time you check to see if it's '\n'. You want to call mygetch() before you do the comparison:
int i = 0;
for (;;)
{
c = mygetch();
if (c == '\n')
break;
c = mygetch();
pass[i++] = c;
}
pass[i] = '\0';
Over and above the correctly diagnosed issue with strcat() taking two strings -- why did you ignore the compiler warnings, or if there were no warnings, why don't you have warnings turned on? As I was saying, over and above that problem, you also need to consider what happens if you get EOF, and you also need to worry about the initial value of 'c' (which could accidentally be '\n' though it probably isn't).
That leads to code like this:
int c;
char pass[20] = "";
char *end = pass + sizeof(pass) - 1;
char *dst = pass;
while ((c = getchar()) != EOF && c != '\n' && dst < end)
*dst++ = c;
*dst = '\0'; // Ensure null termination
I switched from 'mygetch()' to 'getchar()' - primarily because what I say applies to that and might not apply to your 'mygetch()' function; we don't have a specification of what that function does on EOF.
Alternatively, if you must use strcat(), you still need to keep a track on the length of the string, but you can do:
char c[2] = "";
char pass[20] = "";
char *end = pass + sizeof(pass) - 1;
char *dst = pass;
while (c[0] != '\n' && dst < end)
{
c[0] = mygetch();
strcat(dst, c);
dst++;
}
Not as elegant as all that - using strcat() in context is overkill. You could, I suppose, do simple counting and repeatedly use strcat(pass, c), but that has quadratic behaviour as strcat() has to skip of 0, 1, 2, 3, ... characters on the subsequent iterations. By contrast, the solution where dst points to the NUL at the end of the string means that strcat() doesn't have to skip anything. With a fixed size addition of 1 character, though, you're probably better off with the first loop.

Resources