I try to read a file character by character on C and i get Segmentation fault, no idea why and how can i debug it..
int textdump(const char *filename)
{
int count = 0;
FILE *file;
file = fopen(filename,"r");
char letter;
while(!feof(file)) {
letter = fgetc(file);
if (isprint(letter)) {
printf("%c",letter);
count++;
}
else {
printf("?");
}
}
fclose(file);
return count;
}
Okay, so your code has a bunch of mistakes that are common in beginner code.
Here's how to do it along the same lines, but hopefully fixing the errors:
size_t textdump(const char *filename)
{
size_t count = 0;
FILE * const file = fopen(filename, "rt");
if(file == NULL)
return 0;
while (1) {
const int ch = fgetc(file);
if(ch == EOF)
break;
if(isprint(ch) {
putc(ch, stdout);
++count;
}
else
putc('?', stdout);
}
fclose(file);
return count;
}
This:
Checks that the fopen() succeeds before relying on the file pointer being valid.
Uses the proper type for fgetc()'s return value, which is int.
Corrects the while(!feof() anti-pattern.
Uses fputc() for single-character output, lighter than printf().
Uses size_t to represent the count.
I'm not saying this is optimal, it still does single-character reading for instance (but buffered so it shouldn't be too bad). But it should be better.
Related
I have a practice question in C that asks me to create a function that only copies part of a file to another one. The restrictions are that lines with greater than maxlen characters are not copied to the new file, and the newline character does not count, so it should not be copied. Part of my function says that if a file does not exist, it should explicitly say so, and I am getting those error messages when I run that code; however, I can see that the files are created are inside my folder. Whenever I open the file I'm trying to read after running the code, I get this:
./Debug/main.c.o ./Debug/dot.c.o ./Debug/dataBase.c.o ./Debug/intPrompt.c.o ./Debug/numWords.c.o ./Debug/LinkedList.c.o
Below is my code :
void shortLines(char* f1, char* f2, int maxlen) {
FILE* fp = fopen(f1, "r");
FILE* fp2 = fopen(f2, "w");
if (fp == NULL) {
perror("File does not exist");
}
if (fp2 == NULL) {
perror("File does not exist");
}
char singleLine[maxlen];
char check;
size_t len;
do {
fgets(singleLine, maxlen, fp);
len = strlen(singleLine);
if (singleLine[len-1] == '\n') {
singleLine[len-1] = '\0';
}
fprintf(fp2, "%s", singleLine);
} while ((check=getc(fp) != EOF));
}
int main(int argc, char **argv) {
shortLines("Andrew.txt", "Andrew2.txt", 25);
return 0;
}
I just made new files called Andrew.txt and Andrew2.txt and these ones seem to be working for some strange reason. Regardless, there were a few problems in the code. First of all, after fgets is called, I needed to make sure to flush out the remaining characters in the line. I do this with a while loop and fgetc. If I reach an EOF, then I continue, and then fgets also returns an EOF, thus breaking the outer loop.
void shortLines(char* f1, char* f2, int maxlen) {
FILE* fp = fopen(f1, "r");
FILE* fp2 = fopen(f2, "w");
if (fp == NULL) {
perror(f1);
}
if (fp2 == NULL) {
perror(f2);
}
char line[maxlen+1];
size_t len;
char c;
while (fgets(line, maxlen+1, fp) != NULL) {
len = strlen(line);
if (len == maxlen) {
while ((c=fgetc(fp)) != '\n') {
if (feof(fp)) {
break;
}
}
continue;
}
if (line[len-1] == '\n') {
line[len-1] = '\0';
}
fprintf(fp2, "%s\n", line);
}
}
I am trying to read from files and write to a temp file. However, I am stuck in an infinite loop right now. The function below is called multiple times by a recursive function that goes through directories to read files.
My approach is that I would read each word from one file, then those words to another file.
The function I have works fine if I just print out each word. It prints out each word in each file in all directories. However, when I try to start writing to a temp file (the code commented out), I am stuck in the while loop.
On the other hand, if I just call the function once in a test program where I just read from one file in the current directory, and write to a temp file, it's fine.
This is what I have (fileName when passed in is actually the absolute path, and I do ../tmp so it does not get caught in the recursion function):
void fileReadWrite(char *pattern, char *before, char *replace, char *fileName) {
FILE *file = fopen(fileName, "r");
if (file != NULL) {
int ch, word = 0;
while ((ch = fgetc(file)) != EOF) {
if (isspace(ch) || ispunct(ch)) {
if (word) {
word = 0;
putchar('\n');
}
}
else {
word = 1;
putchar(ch);
/*
FILE *f = fopen("../tmp", "wb"); // create and write
if (f == NULL)
{
printf("Error opening file!\n");
exit(1);
}
fprintf(f, "Some text"); // Or fprintf(f, ch);
fclose(f);
*/
}
}
fclose(file);
}
}
There's nothing in your code that suggests an infinite loop. However, if fileName is very large, you could be opening and closing "..\tmp" millions of times. As Joachim Pileborg points out in the comments, you should open that file just once at the beginning of your function, and close it again at the end.
If you want to convince yourself that you are not in an infinite loop, print out the value of ch on each iteration.
Okay so I did this and it worked. But I don't understand why though. Can someone explain it please?
void fileReadWrite(char *pattern, char *before, char *replace, char *fileName) {
FILE *file = fopen(fileName, "r");
FILE *f = fopen("../tmp", "wb"); // MOVE HERE
if (file != NULL) {
int ch, word = 0;
while ((ch = fgetc(file)) != EOF) {
if (isspace(ch) || ispunct(ch)) {
if (word) {
word = 0;
putchar('\n');
}
}
else {
word = 1;
putchar(ch);
/*
if (f == NULL)
{
printf("Error opening file!\n");
exit(1);
}
fprintf(f, "Some text"); // Or fprintf(f, ch);
*/
}
}
fclose(file);
fclose(f); // MOVE HERE
}
}
I am suppose to pass stream, which is a pointer, by reference. So I am passing this as a pointer to a pointer. Can someone please verify my code?
int main(int argc, char** argv)
{
FILE *stream;
printf("LINES: %d\n",scan(stream));
}
int scan(FILE *(*stream))
{
stream = fopen("names.txt", "r");
int ch = 0, lines=0;
while (!feof(*stream))
{
ch = fgetc(*stream);
if (ch == '\n')
{
lines++;
}
}
fclose(*stream);
return lines;
}
No output received.
Your code has design issues. What exactly do you want to achieve?
If you just want to count the lines, make the FILE * local to your function:
int count_lines(const char *filename)
{
FILE *stream = fopen(filename, "r");
int lines = 0;
while (1) {
int c = fgetc(stream);
if (c == EOF) break;
if (c == '\n') lines++;
}
fclose(stream);
return lines;
}
If you want to do a regular file operation (read, write, seek, rewind etc.) to a file that has already been opened with fopen, just pass the handle as FILE *:
int fget_non_space(FILE *stream)
{
int c;
do {
c = fgetc(stream);
} while (isspace(c));
return c;
}
In that case, both fopen and fclose are called outside this function. (You don't call fclose in your program, which you should, even if the operating system makes sure to close the file automatically after exiting.)
Passing a pointer to the file handle, FILE **, makes sense only if you want to change that file handle itself in the function, for example by calling fopen:
int fopen_to_read(FILE **FILE pstream, const char *fn)
{
*pstream = fopen(fn, "r");
return (*pstream != NULL) ? 0 : -1;
}
Even then, it would be better to return the file handle, as fopen does.
Your example code leaves the open filehandle accessible in main, but you don't do anything with it, you don't even close it. Is that what you want? I doubt it.
Use
int scan(FILE **stream) //no need for brackets
{
*stream = fopen("names.txt", "r"); //* is for dereferencing
if(*stream==NULL) // Checking the return value of fopen
{
printf("An error occured when opening 'names.txt'");
return -1;
}
int ch = 0, lines=0;
while ((ch = fgetc(*stream))!=EOF) //while(!feof) is wrong
{
if (ch == '\n')
{
lines++;
}
}
fclose(*stream); // Close the FILE stream after use
return lines;
}
int main(void)
{
FILE *stream;
printf("LINES: %d\n",scan(&stream)); //Pass address of `stream`. The address is of type `FILE**`
}
Replace
stream = fopen("names.txt", "r");
with
*stream = fopen("names.txt", "r");
Also
printf("LINES: %d\n",scan(stream));
with
printf("LINES: %d\n",scan(&stream));
int periodCount(const char *filename) {
FILE * fp;
int n = 0;
if( (fp=fopen(filename,"r")) != NULL) {
while(fgetc(fp)!= EOF) {
if(fgetc(fp)=='.') n++;
fclose(fp);
}
}
return n;
}
Here is my code, it simply should count the number of periods in the file named filename, which contains 15 periods, yet when I try to print 'n' at the end of the program, it seems to only be reading 1 of the periods. I know that the problem is probably within the while loop, but I'm not sure why it's doing it.
You're closing the file after the first character. Also you're skipping every other character as a result of not storing the return from fgetc(). Change to:
int periodCount(const char *filename) {
FILE * fp;
int n = 0, c = 0;
if( (fp=fopen(filename,"r")) != NULL) {
while( (c = fgetc(fp)) != EOF) {
if( c == '.' )
n++;
}
fclose(fp); /* <---- move this line here */
}
return n;
}
Your fclose(fp) should be outside the while loop.
As it is, the code is reading (& discarding) the first character; reading the 2nd character & comparing it to '.'; and closing the file.
There are two problems:
You have two calls to fgetc() but you only test whether one of them returned a dot.
You close the file stream in the body of the loop.
You need something more like:
if ((fp = fopen(filename,"r")) != NULL)
{
int c;
while ((c = fgetc(fp)) != EOF)
{
if (c == '.')
n++;
}
fclose(fp);
}
I'm on a little project of making a little compressor program. For that I want to read a file, say an .exe, and parse it char by char and use some simple dictionary algorithm to encrypt it.
For reading the file I just thout in using a simple code I found:
char *readFile(char *fileName)
{
FILE *file;
char *code = malloc(10000* sizeof(char));
file = fopen(fileName, "rb");
do
{
*code++ = (char)fgetc(file);
} while(*code != EOF);
return code;
}
My problem is that it's seems imposible to read an .exe or any file at all. When making a printf() of "code" nothing is writen.
What can I do?
#BLUEPIXY well identified a code error. See following. Also you return the end of the string and likely want to return the beginning.
do {
// *code++ = (char)fgetc(file);
*code = (char)fgetc(file);
// } while(*code != EOF);
} while(*code++ != EOF);
Something to get you started reading any file.
#include <stdio.h>
#include <ctype.h>
void readFile(const char *fileName) {
FILE *file;
file = fopen(fileName, "rb");
if (file != NULL) {
int ch;
while ((ch = fgetc(file)) != EOF) {
if (isprint(ch)) {
printf("%c", ch);
}
else {
printf("'%02X'", ch);
if (ch == '\n') {
fputs("\n", stdout);
}
}
fclose(file);
}
}
When reading a binary file char-by-char, code typically receives 0 to 255 and EOF, 257 different values.