Currently, I have a parent process piping information to children and reading out of their STDOUT through fgetc. I iterate through rounds and store the file pointer from the first round using fdopen and call it again in the next round.
The issue is, in the first round the read_line results in a perfectly fine read, but in the second round the fgetc hits a segfault.
Error Message:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7791330 in __GI___uflow (fp=0x6041b0) at genops.c:381
381 return *(unsigned char *) fp->_IO_read_ptr++;
Reading Function: (I know it's not the best)
To Clarify. It works the first time. Why won't it work the second?
Many other questions seem to just have a different error.
char* read_line(FILE* file,int currentP, Players *players) {
char* result = malloc(sizeof(char) * 80);
int position = 0;
int next = 0;
for (int i = 0; i < players->players[currentP].position; i++) {
next = fgetc(file);
}
while (1) {
next = fgetc(file);
//players->players[currentP].position++;
if (next == '!') {
return "!";
}
if (next == EOF || next == '\n') {
result[position] = '\0';
return result;
} else {
result[position++] = (char)next;
}
}
}
Related
I'm writing a program that needs to read input one character at a time and transform that input, and I need to be able to differentiate the end of a line (\n) and the end of the stdin. For whatever reason my program just loops infinitely after it gets to the last line and never prints it. I'm wondering why it's never catching EOF? I took out some of the code from the bottom because it's just a ton of if statements replacing characters with uppercase characters and such. I basically just don't understand why my code is never breaking.
#include <stdio.h>
#include <string.h>
int main(void)
{
int MAXCHARS = 79;
int curr;
char currline[MAXCHARS*2];
char lastline[MAXCHARS*2];
memset(currline,0,158);
memset(lastline,0,158);
int pointer = 0;
while (1)
{
curr = getchar();
if (curr == EOF)
{
for (int i = 0; i < pointer; i++)
{
printf("%c", currline[i]);
}
break;
}
if (curr == '\n')
{
if (currline == lastline)
{
pointer = 0;
}
else
{
strcpy(lastline,currline);
for (int i = 0; i < pointer; i++)
{
printf("%c", currline[i]);
}
pointer = 0;
}
}
}
}
As far as I can understand, your program never reaches that block of code, because it never gets EOF. Try Ctrl+Z for Windows or Ctrl+D for Linux.
Also see https://en.wikipedia.org/wiki/End-of-file and What is considered as EOF in stdin?
I'm currently reading a pipe from a child process as follows. The problem is that while the fgetc is working, it's not starting a new line. It's continuously reading so my program always breaks at '!'
E.g:
! -> !example -> !exampleExample
instead of
! -> example -> Example
Below is my read function, but the pipe is basically not clearing when read.
char* read_line(FILE* file) {
char* result = malloc(sizeof(char) * 80);
int position = 0;
int next = 0;
while (1) {
next = fgetc(file);
if (next == '!') {
return "!";
}
if (next == EOF || next == '\n') {
result[position] = '\0';
return result;
} else {
result[position++] = (char)next;
}
}
}
There is a possibility of crash as there is no limit over the access result[position]. The memset is not done after malloc. Ignoring all these the issue seems to be in the function calling the read_line. Check on the handling of the returned address , as return "!" is not correct.
I'm trying to write a program of a basic shell that exits at EOF and handles SIGINT without quitting. It was working within one functionless c file but upon creating functions I ran into an error where EOF and SIGNINT would cause seg faults. I'm unsure what's causing this and hoping that someone will spot something I did not. Below is the function I think causing the issue, its the first thing done after the Shell reads a command (or where I'm applying signals).
int check_redirect(char *line, int flag)
{
int n = 0;
if (line == NULL) return (flag);
else
{
do
{
if (line[n] == '>') flag = 1;
n++;
}while (line[n] != '\n');
}
return (flag);
}
This is where the function is called:
char buffer[15];
time_t now = time(NULL);
strftime(buffer, 15, "[%d/%m %H:%M]", localtime(&now) );
fprintf(stdout, "%s # ", buffer);
signal(SIGINT, SIG_IGN);
read = getline (&line, &len, stdin);
signal(SIGINT, SIG_DFL);
flag = check_redirect(line, flag);
Hopefully this is clear enough. This is at the beginning of a loop, which is looking for input to execute as a command, having printed out the prompt (date and time #). The commands work mostly but act as if they are lost occasionally, which I think may be related to this signal processing error.
Thanks in advance.
Seg fault can occur from an infinite loop
You have the potential for an infinite loop here:
... }while (line[n] != '\n');
Suggest checking for more than just the \n character.
You could use strstr(line, "\n"); to verify newline exists before entering loop, for example.
Change your code to
int check_redirect(char *line, int flag, int len)
{
int n = 0;
if (line != NULL)
{
do
{
if (line[n] == '>')
{
flag = 1;
}
n++;
}
while ((line[n] != '\n') && (n<len))
}
return (flag);
}
call it with:
flag = check_redirect(line, flag, read);
This question already has an answer here:
Print last 10 lines of file or stdin with read write and lseek [closed]
(1 answer)
Closed 7 years ago.
I'm working on an assignment where part of it is to read from stdin using the system function read(), and then print the last 10 lines and so far I've got this:
int tailSTD()
{
char *lines = malloc(1);
char buffer[10];
int cmdCount = 0, buffCount, rState;
while((rState = read(STDOUT_FILENO, buffer, 10)) > 0)
{
if(rState < 0)
{
if(errno == EINTR) rState = 0;
else
{
perror("read()");
return 0;
}
}
else if (rState == 0) break;
lines = realloc(lines, strlen(lines) + strlen(buffer));
for(buffCount = 0; buffCount < strlen(buffer); buffCount++)
{
lines[cmdCount] = buffer[buffCount];
cmdCount++;
}
}
printf("do we get this far?");
printSTDLines(lines);
return 0;
}
The problem is that I get a segmentation fault somewhere along the loop and I\m not sure where, this worked with fgets(), and I simply modified it just because it just HAS to be done with read(). It's probably very messy, for which I apologize, but it just has to be done in this manner. I know the problem is here, because it never gets to the last printf before printSTDLines.
Here's printSTDLines if you need it:
void printSTDLines(char *lines)
{
int lineCount = strlen(lines), newLineCount = 0;
while(newLineCount < 10)
{
if(lines[lineCount] == '\n')
{
newLineCount++;
}
lineCount--;
}
int readSize = strlen(lines) - lineCount;
for(lineCount = readSize; lineCount < sizeof(lines); lineCount++)
{
write(STDOUT_FILENO, &lines[lineCount], 1);
}
}
You are using strlen(lines) but you never nul terminate it. The strlen() function expects to find a '\0' byte to tell where the end of the "string" is, you don't add that byte to any of your arrays and that invokes undefined behavior, one possible consequence of that is a segmentation fault.
Also, this
for(lineCount = readSize; lineCount < sizeof(lines); lineCount++)
seems wrong, the sizeof operator doesn't work for an dynamically allocated array, in this case lines is a pointer and that means sizeof is giving you the size of a pointer and by no means the length of the array which is apparently what you want.
To use the length of the array inside printSTDLine() you need to pass it as a parameter.
I'm very new to C and I'm still learning the basics. I'm creating an application that reads in a text file and breaks down the words individually. My intention will be to count the amount of times each word occurs.
Anyway, the last do-while loop in the code below executes fine, and then crashes. This loop prints memory address to this word (pointer) and then prints the word. It accomplishes this fine, and then crashes on the last iteration. My intention is to push this memory address into a singly linked list, albeit once it's stopped crashing.
Also, just a quick mention regarding the array sizes below; I yet figured out how to set the correct size needed to hold the word character array etc because you must define the size before the array is filled, and I don't know how to do this. Hence why I've set them to 1024.
#include<stdio.h>
#include<string.h>
int main (int argc, char **argv) {
FILE * pFile;
int c;
int n = 0;
char *wp;
char wordArray[1024];
char delims[] = " "; // delims spaces in the word array.
char *result = NULL;
result = strtok(wordArray, delims);
char holder[1024];
pFile=fopen (argv[1],"r");
if (pFile == NULL) perror ("Error opening file");
else {
do {
c = fgetc (pFile);
wordArray[n] = c;
n++;
} while (c != EOF);
n = 0;
fclose (pFile);
do {
result = strtok(NULL, delims);
holder[n] = *result; // holder stores the value of 'result', which should be a word.
wp = &holder[n]; // wp points to the address of 'holder' which holds the 'result'.
n++;
printf("Pointer value = %d\n", wp); // Prints the address of holder.
printf("Result is \"%s\"\n", result); // Prints the 'result' which is a word from the array.
//sl_push_front(&wp); // Push address onto stack.
} while (result != NULL);
}
return 0;
}
Please ignore the bad program structure, as I mentioned, I'm new to this!
Thanks
As others have pointed out, your second loop attempts to dereference result before you check for it being NULL. Restructure your code as follows:
result = strtok( wordArray, delims ); // do this *after* you have read data into
// wordArray
while( result != NULL )
{
holder[n] = *result;
...
result = strtok( NULL, delims );
}
Although...
You're attempting to read the entire contents of the file into memory before breaking it up into words; that's not going to work for files bigger than the size of your buffer (currently 1K). If I may make a suggestion, change your code such that you're reading individual words as you go. Here's an example that breaks the input stream up into words delimited by whitespace (blanks, newlines, tabs, etc.) and punctuation (period, comma, etc.):
#include <stdio.h>
#include <ctype.h>
int main(int argc, char **argv)
{
char buffer[1024];
int c;
size_t n = 0;
FILE *input = stdin;
if( argc > 1 )
{
input = fopen( argv[1], "r");
if (!input)
input = stdin;
}
while(( c = fgetc(input)) != EOF )
{
if (isspace(c) || ispunct(c))
{
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
n = 0;
}
}
else
{
buffer[n++] = c;
}
}
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
}
fclose(input);
return 0;
}
No warranties express or implied (having pounded this out before 7:00 a.m.). But it should give you a flavor of how to parse a file as you go. If nothing else, it avoids using strtok, which is not the greatest of tools for parsing input. You should be able to adapt this general structure to your code. For best results, you should abstract that out into its own function:
int getNextWord(FILE *stream, char *buf, size_t bufsize)
{
int c;
size_t n = 0;
while(( c = fgetc(input)) != EOF && n < bufsize)
{
if (isspace(c) || ispunct(c))
{
if (n > 0)
{
buf[n] = 0;
n = 0;
}
}
else
{
buffer[n++] = c;
}
}
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
}
if (n == 0)
return 0;
else
return 1;
}
and you would call it like
void foo(void)
{
char word[SOME_SIZE];
...
while (getNextWord(inFile, word, sizeof word))
{
do_something_with(word);
}
...
}
If you expect in your do...while code, that result could be null (this is the condition for loop break), how do you think this code-line:
holder[n] = *result;
must work? It seems to me, that it is the reason for crashing in your program.
Change do while loop to while
use
while (condition)
{
}
instead of
do {
}while(condition)
It is crashing because you are trying to derefrance a NULL pointer result in do while loop.
I work mostly with Objective-C and was just looking at your question for fun, but I may have a solution.
Before setting n=0; after your first do-while loop, create another variable called totalWords and set it equal to n, totalWords can be declared anywhere within the file (except within one of the do-while loops), but can be defined at the top to the else block since its lifetime is short:
totalWords = n;
then you can set n back to zero:
n = 0;
Your conditional for the final do-while loop should then say:
...
} while (n <= ++totalWords);
The logic behind the application will thus say, count the words in the file (there are n words, which is the totalWords in the file). When program prints the results to the console, it will run the second do-while loop, which will run until n is one result past the value of totalWords (this ensures that you print the final word).
Alternately, it is better practice and clearer for other programmers to use a loop and a half:
do {
result = strtok(NULL, delims);
holder[n] = *result;
wp = &holder[n];
printf("Pointer value = %d\n", wp);
printf("Result is \"%s\"\n", result);
//sl_push_front(&wp); // Push address onto stack.
if (n == totalWords) break; // This forces the program to exit the do-while after we have printed the last word
n++; // We only need to increment if we have not reached the last word
// if our logic is bad, we will enter an infinite loop, which will tell us while testing that our logic is bad.
} while (true);