this is my first question asked on here so if I'm not following the formatting rules here please forgive me. I am writing a program in C which requires me to read a few lines from a file. I am attempting to put each line into a cstring. I have declared a 2D character array called buf which is to hold each of the 5 lines from the file. The relevant code is shown below
#include <stdlib.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/un.h> /* UNIX domain header */
void FillBuffersForSender();
char buf[5][2000]; //Buffer for 5 frames of output
int main()
{
FillBuffersForSender();
return 0;
}
void FillBuffersForSender(){
FILE *fp;
int line = 0;
char* temp = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("frames.txt", "r");
printf("At the beginning of Fill Buffers loop.\n");
//while ((read = getline(&temp, &len, fp)) != -1){
while(line < 5){
//fprintf(stderr, "Read in: %s\n", temp);
fgets(temp, 2000, fp);
strcpy(buf[line], temp);
line++;
fprintf(stderr, "Line contains: %s.\n", temp);
temp = NULL;
}
while(line != 0){
fprintf(stderr, "Line contains: %s.\n", buf[line]);
line--;
}
}
The line
strcpy(buf[line], temp);
is causing a segmentation fault. I have tried this numerous ways, and cannot seem to get it to work. I am not used to C, but have been tasked with writing a bidirectional sliding window protocol in it. I keep having problems with super basic issues like this! If this were in C++, I'd be done already. Any help anyone could provide would be incredible. Thank you.
temp needs to point to an allocated buffer that fgets can write into.
In C programming, error checking is an important part of every program (in fact sometimes it seems like there's more error handling code than functional code). The code should check the return value from every function to make sure that it worked, e.g. if fopen returns NULL then it wasn't able to open the file, likewise if fgets returns NULL it wasn't able to read a line.
Also, the code needs to clean up after itself. For example, there is no destructor that closes a file when the file pointer goes out of scope, so the code needs to call fclose explicitly to close the file when it's finished with the file.
Finally, note that many of the C library functions have quirks that need to be understood, and properly handled. You can learn about these quirks by reading the man pages for the functions. For example, the fgets function will leave the newline character \n at the end of each line that it reads. But the last line of a file may not have a newline character. So when using fgets, it's good practice to strip the newline.
With all that in mind, the code should look like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLINE 5
#define MAXLENGTH 2000
static char buffer[MAXLINE][MAXLENGTH];
void FillBufferForSender(void)
{
char *filename = "frames.txt";
FILE *fp;
if ((fp = fopen(filename, "r")) == NULL)
{
printf("file '%s' does not exist\n", filename);
exit(1);
}
for (int i = 0; i < MAXLINE; i++)
{
// read a line
if (fgets( buffer[i], MAXLENGTH, fp ) == NULL)
{
printf("file does not have %d lines\n", MAXLINE);
exit(1);
}
// strip the newline, if any
size_t newline = strcspn(buffer[i], "\n");
buffer[i][newline] = '\0';
}
fclose(fp);
}
int main(void)
{
FillBufferForSender();
for (int i = 0; i < MAXLINE; i++)
printf("%s\n", buffer[i]);
}
Note: for an explanation of how strcspn is used to strip the newline, see this answer.
When it comes to C you have to think of the memory. Where is the memory for a point with NULL assigned to it? How can we copy something to somewhere that we have no space for?
Related
I am new to C and I came across an issue when using fscanf to read all strings from a .txt file.
The code is as follow:
#include <stdlib.h>
#include <stdio.h>
int main() {
FILE *spIn;
char *numIn;
spIn = fopen("data.txt", "r");
if (spIn == NULL) {
printf("Can't Open This File \n");
}
while ((fscanf(spIn, "%s", numIn)) == 1) {
printf("%s\n", numIn);
};
fclose(spIn);
return 1;
}
This throws an error: Segmentation fault: 11.
The original data on txt file is:
1 2 345 rrtts46
dfddcd gh 21
789 kl
a mix of ints, strings, white space and newline characters.
At least 4 candidate undefined behaviors (UB) that could lead to a fault of some kind.
Code fails to pass to fscanf(spIn,"%s",numIn) an initialized pointer.
Code calls fscanf() even if fopen() fails.
Code calls fclose() even if fopen() fails.
No width limit in fscanf(spIn,"%s",numIn)), worse than gets().
Text files really do not have strings ('\0' terminated data) nor int, they have lines (various characters with a '\n' termination).
To read a line in and save as a string, use fgets(). Do not use fscanf() to read lines of data.
#include <stdlib.h>
#include <stdio.h>
int main() {
FILE *spIn = fopen("data.txt", "r");
if (spIn == NULL) {
printf("Can't Open This File \n");
} else {
char buf[100];
while (fgets(buf, sizeof buf, spIn)) {
printf("%s", buf);
}
fclose(spIn);
}
}
char* numIn is a pointer, and it is uninitalized, you can't really store anything in it, you need to either allocate memory for it or make it point to some valid memory location:
#include<stdlib.h> // for malloc
char* numIn = malloc(100); // space for 99 char + null terminator byte
//...
while ((fscanf(spIn, "%99s", numIn)) == 1)
{
printf("%s\n",numIn);
};
Or:
char str[100];
char *numIn = str;
Which in this small code makes little sense, you should probably make numIn a fixed size array to begin with:
char numIn[100];
Note that that you should use a width specifier in *scanf to avoid buffer overflow. This still has a problem though, it will read word by word, instead of line by line.
Looking at your input file, using fgets seems like a better option, it can read complete lines, including spaces:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
FILE *spIn;
char numIn[100];
spIn = fopen("data.txt", "r");
if (spIn != NULL)
{
while ((fgets(numIn, sizeof numIn, spIn)))
{
numIn[strcspn(numIn, "\n")] = '\0'; // removing \n
printf("%s\n", numIn);
}
fclose(spIn);
}
else
{
perror("Can't Open This File");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Since fgets also parses the \n character, I'm removing it with strcspn.
Though you do verify the return value of fopen the execution continues even if it fails to open, I also addressed that issue.
I have a buffer and I want to read a pascal file and put content in the buffer. Then I want to add '$' sign in the end of buffer. When I tried to do it i get only the last row from my pascal file into buffer I don't why. please help. Here is my code!
FILE *fp = fopen("test.pas", "r");
while(!feof(fp)){
fscanf(fp, "%s", buffer);
}
strcat(buffer,"$"); fclose(fp);
You are reading the lines, the problem is that you are overwriting them over and over again in your buffer, so only the last one stays.
A good way to do this is to use fscanf in the while condition, this way you'll have a sound stop condition and you can verify the read results, which should allways be done.
You can do something like this:
Live demo
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINES 100 //nr of lines
int main() {
//array of 100 pointers to char, so 100 lines max, adapt it to you needs
//should be the equal or larger than the max number of lines to be read
char *buffer[LINES];
FILE *fp;
int i = 0;
//checking the opened file is also a good practice
if (!(fp = fopen("test.pas", "r"))) {
perror("Not able to open file!");
return 1;
}
do {
if (!(buffer[i] = malloc(100))) { //allocate memory for each line
perror("Memory allocation failed"); //checking memory allocation
return 1;
}
}while (fscanf(fp, "%99s", buffer[i]) == 1 && strcat(buffer[i], "$") && i++ < LINES - 1);
buffer[i] = NULL; // sentinel, marks the end of the array of strings
i = 0; //reset i
while (buffer[i]) {
puts(buffer[i]); //print each line
free(buffer[i]); //free memory
i++;
}
fclose(fp);
}
Note that fscanf() reads until the next blank space, so for strings with more than 1 word you should use something like fgets or you if you use UNIX, getline().
feof is not the best option as you can see in
Why is “while ( !feof (file) )” always wrong?
The standard actually exemplifies the correct usage of feof ISO/IEC9899:2017 N2176 § 7.21.6.2 - 19
So I have the txt file from which I need to read the number of students written in that file, and because every student is in separate line, it means that I need to read the number of lines in that document. So I need to:
Print all lines from that document
Write the number of lines from that document.
So, I write this:
#include "stdafx.h"
#include <stdio.h>
int _tmain(int argc, _TCHAR* Argo[]){
FILE *student;
char brst[255];
student = fopen("student.txt", "r");
while(what kind of condition to put here?)
{
fgetc(brst, 255, (FILE*)student);
printf("%s\n", brst);
}
return 0;
}
Ok, I understand that I can use the same loop for printing and calculating the number of lines, but I can't find any working rule to end the loop. Every rule I tried caused an endless loop. I tried brst != EOF, brst != \0. So, it works fine and print all elements of the document fine, and then it start printing the last line of document without end. So any suggestions? I need to do this homework in C language, and I am using VS 2012 C++ compiler.
OP's code is close but needs to use fgets() rather than fgetc() and use the return value of fgets() to detect when to quit, it will be NULL #Weather Vane. Also add a line counter.
#include <stdio.h>
int main(void) {
FILE *student = fopen("student.txt", "r");
unsigned line_count = 0;
if (student) {
char brst[255];
// fgetc(brst, 255, (FILE*)student);
while (fgets(brst, sizeof brst, student)) {
line_count++;
printf("%u %s", line_count, brst);
}
fclose(student);
}
printf("Line Count %u\n", line_count);
return 0;
}
Try this:
#include "stdafx.h"
#include <stdio.h>
int _tmain(int argc, _TCHAR* Argo[]){
FILE *student;
char brst[255];
char* result = NULL;
//Ensure file open works, if it doesn't quit
if ((student = fopen("student.txt", "r")) == NULL)
{
printf("Failed to load file\n");
return 1;
}
//Read in the file
for ( (result = fgets( brst, sizeof(brst), student));
!feof(student);
(result = fgets( brst, sizeof(brst), student)) )
{
if ( result == NULL ) break; //I've worked on embedded systems where this actually ment waiting on data, not EOF, so a 'continue' would go here instead of break in that case
printf("%s\n", brst);
}
fclose( student );
return 0;
}
feof() is only true after you've read past the end of the file. Using a for with two identical reads, and feof() on the conditional is a simple way to ensure you read the file as expected.
Use feof() to check for an eof condition.
You are correctly reading the file line-by-line, but use fgets(), not fgetc() - and the cast is not needed.
Then use sscanf() to assign the line data to variables (or some "safe" form of it).
It's been years since I programmed in C, and so I've been struggling a lot just to do a simply "get filename & path from stdin, read file, print file to stdout" task, which I know shouldn't be that hard but ya. Here is my code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(void) {
int c;
FILE *file;
//scanf("%s", filename);
char *filename;
filename = (char *)malloc(200 * sizeof(char));
read(STDIN_FILENO, filename, 200);
printf("%s", filename);
file = fopen(filename, "r");
if (file) {
while ((c = getc(file)) != EOF)
putchar(c);
fclose(file);
} else {
printf("File not found.");
}
printf("\n");
return(0);
}
I my code continues to simply print out File not found., when I know for a fact my file path and everything is correct (not only because I literally drop it and past it into terminal from my folder with Mac OSX El Capitan - what a lovely feature, but also) because I had a different version of this program using scanf which found the file and read it perfectly fine, (as you can see I have it commented out on my code).
There is another program I'm writing that just uses this one, and I got rid of the scanf because I think it was negatively affecting other things in that program, so I want to be able to use read()
If anyone has any advice on how I can fix this or why this isn't working, that would be greatly appreciated as I've been at this for hours already and would very much like to move on to my actual program that I need to code!
THANKS A BUNCH
You must remove the '\n' new line character that is being read and stored into the filename buffer.
One of the many was to do it is include string.h and after reading the filename
char *newline = strchr(filename, '\n');
if (newline != NULL)
*newline = '\0';
Also, use fgets() instead of read() because that way the program is more portable. And more importantly, read() will not add the null terminator which is very important in order to use the buffer as a string — to pass it to fopen() for example — correctly. If you want to use read try something like this
ssize_t length;
char filename[200];
length = read(STDIN_FILENO, filename, sizeof(filename) - 1);
if (length <= 0)
return -1; // No input or input error
if (filename[length] == '\n')
filename[--length] = '\0';
else
filename[length] = '\0';
But otherwise, try this which is simpler
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
FILE *file;
char filename[200];
char *newline;
if (fgets(filename, sizeof(filename), stdin) == NULL)
return -1; // Input error / EOF
newline = strchr(filename, '\n');
if (newline) // ? is a newline present?
*newline = '\0';
printf("**%s**\n", filename); // ** will help checking for
// the presence of white spaces.
file = fopen(filename, "r");
if (file) {
int chr;
while ((chr = fgetc(file)) != EOF)
fputc(chr, stdout);
fclose(file);
} else {
printf("File not found.");
}
printf("\n");
return 0;
}
I'm trying to get input from the user in the console, but I'm having problems with the function getline() in my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <memory.h>
#include <sys/wait.h>
#include <errno.h>
int main(int argc, char *argv[])
{
//check that the number of arguments given is valid
if (argc != 2){
printf("Error: arguments. \nThe file should only take one argument which is the name of the level\n");
exit(1);
}
char test[5];
int nb_lettres=strlen(argv[1]);
strncpy(test,argv[1]+nb_lettres-4,4);
//check that the file given is either a .tgz or a .tar
test[4]='\0';
if(strcmp(test,".tar")!=0 && strcmp(test,".tgz")!=0)
{
printf("Error: arguments. \nThe argument should be a file having the extension .tar or .tgz \n");
exit(2);
}
int status; //START OF THE PART CONTAINING THE PROBLEM
pid_t pid;
//create the folder then move to it, then extract the tar
if((pid=fork())!=0){
if(fork()){
execlp("mkdir","mkdir","leaSHdir",NULL);
}
//waiting to make sure we don't try to go in the folder before it's fully created
wait(&status);
execlp("tar","tar", "-xf", argv[1], "-C", "leaSHdir/",NULL);
}
waitpid(pid,&status,0);
printf("Extracting the files..\n");
sleep(1); //END OF THE PART CONTAINING THE PROBLEM
//Read the meta file
FILE *file;
chdir("./leaSHdir");
file=fopen("meta","r");
if (file==NULL){
// printf("Oh dear, something went wrong with read()! %s\n", strerror(errno));
printf("Error: meta. \nImpossible to read the meta file. Please check that it does exist (without looking in, vile cheater)\n");
exit(3);
}
char *line=NULL;
size_t len=0;
//Saving the commands which will be used by the user
char *result=NULL;
char **commands = malloc(5 * sizeof *commands);
int i=0;
if(commands==NULL){
printf("Error: memory. \nA problem occured with the memory while creating a pointer\n");
exit(4);
}
while(getline(&line,&len,file)!=-1){
if(strstr(line,"$")!=NULL){
commands[i]=(malloc(strlen(line)));
strcpy(commands[i],line+2);
//if the array is full,we add space for the next incoming command
if(i >= 4){
commands=realloc(commands,sizeof *commands *(i+2));
}
i++;
}
if(line[0]=='>'){
result=malloc(strlen(line));
strcpy(result,line+2);
}
}
int a = 0;
for (a = 0;a<i;a++){
printf("%s",commands[a]);
}
printf("%s",result);
printf("Erasing meta..");
unlink("meta");
printf("meta erased.\n");
int c;
while((c = getchar()) != '\n' && c != EOF){
printf("rien\n");
}
ssize_t r = getline(&line,&len,stdin);
printf("%d '%s' %d",(int) r, line, c);
char machin[2555];
scanf("%s",machin);
printf("%s test",machin);
free(commands);
free(result);
return 0;
}
When I execute this code, the last getline is completely skipped (the first one is working without any problem), which I don't see why. I've also tried using different functions (fgets, scanf) and both were also skipped.
Thanks in advance for any help which can be provided :)
Edit:
Changed the faulty getline line with ssize_t r = getline(&line,&len,stdin); printf("%d '%s' %d",(int) r, line, c);, here's the result:
cat
ls
man
Bravo! C'est ici!//this line and the 3 other lines before are the lines read by the first getline which is working
Erasing meta..meta erased.
-1 '> Bravo! C'est ici!
' -1
So basically, I don't even have time to type anything, I get this result directly without entering anything. Also the content of line isn't changed after the second getline considering it still contains the result from the first getline.
Edit 2 :
Okay, I think I found from where comes the problem: Basically, it's from a part of the code i didn't put in the extract there because I though it was not related at all with my current problem, so I've edited the whole extract to put it fully. I've put two comments to mark the part containing the problem. Although I don't see what could be causing it, considering this part contains only forks.
Although, sorry for the trouble, guys, should have put the whole code at the start
Last edit:
Figured out what was the problem: if((pid=fork())!=0){ which means that once my forks ended I was working on the child process and not on the father as I thought. Once I've changed it to if((pid=fork())==0){ everything worked fine. Thanks for the help :)
[Edit]
After some edits:
OP's problem occurs when using stdin after fork().
Similar to Two processes reading the same stdin
Code is unable to take in additional input as stdin has all ready reached the EOF condition or a rare IO error. That is the -1 return values from getline() and getchar(). line simply retains its former contents as nothing was changed.
char c;
while((c = getchar()) != '\n' && c != EOF);
ssize_t r = getline(&line,&len,stdin); //getline not working
printf("%d '%s' %d",(int) r, line, c);
-1 '> Bravo! C'est ici!
' -1
Additional issue: realloc() too late.
strcpy(commands[5],line+2); writes to unallocated memory.
char **commands=malloc(sizeof(char**)*5);
int i=0;
...
// In loop, i becomes 5.
...
strcpy(commands[i],line+2);
if (i > 5){
commands=realloc(commands,sizeof(char**)*(i+2));
Put somtehing before getilne to consume the trailing '\n' character. For example:
while ( getchar() != '\n' );
getline(&line,&len,stdin);