I'm writing a C program, and it is dealing with fairly large files (~4MB .txt files). The program opens the big file and splits it up into a bunch of little files, before testing each of the little files. I've written a function that later opens those files, tests to make sure the full section was copied, and returns 1 if the section was not effectively copied (a different bug I'm having is that sometimes it only copies the first 2 words of a section). When I compile & run my program through koding.com (which uses the gcc compiler), it works perfectly for all test files. However, when I try to run it locally on my MacBook through Terminal (I run Lion, and have the version of gcc included in Xcode 4.6.3), it gives me "Segmentation fault: 11" and quits, but only when I use it on certain files (e.g. a 3.9MB file gives the segfault, but a 2.7MB file does not).
Here is how the function is called:
for(i=1;tableArray[i].count!=0;i++)
{
strcpy(word,tableArray[i].shortName);
strcat(word,".txt");
if(fopen(word, "r")!=NULL)
{
testFile = fopen(word, "r");
problems[i] = checkFile(testFile);
fclose(testFile);
}
}
And here is the function:
int checkFile(FILE *file)
{
char word[NAMELEN];
int count = 0;
while(fscanf(file, "%s", word)!=EOF)
count++;
if(count<3)
return(1);
else return(0);
}
Any insight is much appreciated. Thanks!
Related
I am trying to make a small program in C which reads in a file and calculates a CRC on the contents. I created the program in netbeans and in the IDE everything works. When I build the project with GCC and run the generated exe the program fails when reading in the file. The file is 1.3 Mb.
When reading in the file I eventually get the error "Internal error: TP_NUM_W_BUFS too small: 50"
My read code is fairly simple, it does very little line processing.
while (fgets(line, HEX_LINE_LENGTH, fp))
{
int len = strlen(line);
line[len] = line[len-1];
line[len-1] = '\r';
memcpy(&hex_lines[num_lines], line, HEX_LINE_LENGTH);
num_lines++;
printf("%s\n", line);
memset(line, 0, HEX_LINE_LENGTH);
}
I am seeing a new issue. When reading in my file via the netbeans IDE everything works fine. When I compile the program from a command line with
g++ main.c crc_calculator.c crc_calculator.h -o crc
I get a crc.exe file. Running this will read in my file but will report that twice as many lines have been read than actually exist.
I wrote the following code in GDB online debugger :
#include <stdio.h>
int main()
{
printf("jkjkkjkj");
int p , n;
FILE *fp;
printf("jkjkkjkj2");
fp = fopen("abc.txt","r");
while ( (n = getc(fp))!= EOF)
{
printf( "the chareacter here is %d \n", n);
}
n = fclose(fp);
return 0;
}
While executing the code I am getting a segmentation fault at the line where I am trying to fetch the characters from the file. I know that as the file does not exist the segmentation fault error is coming.
However, what intrigues me is the absence of the messages that I am trying to print on the screen. I tried checking on debugger and once I found:
optimized out written near the line no
However, I tried putting getchar() here and there, the messages got printed on the screen even if the segmentation fault persists.
How to explain this? Why is this happening? Why are the messages printed when I am putting getchar() at different places?
I had tried writing this code on a Solaris server and compiling using GCC. The code got compiled but I did not get any output message even when a file with the name provided in the directory existed.
As answered by Yunnosch, you probably forgot to check against failure of fopen(3). A better habit is to always check that, at least by coding:
fp = fopen("abc.txt","r");
if (fp == NULL) { perror("fopen abc.txt"); exit(EXIT_FAILURE); };
and take the habit of doing at least that everywhere. Using perror(3) (or strerror(3) with errno(3)) is a useful habit to get, since you want some reason related to the failure (given by errno perhaps thru perror).
More generally, always read the documentation of functions that you are using (for standard functions, at least on some reference website, and possibly in the C11 standard n1570), and take care of handling their failure (at the very least, by checking against failure and exiting with a useful message to stderr); for Unix functions, see their man pages (on Linux, start on intro(2) and intro(3); for Solaris, start with intro(2) & intro(3)..). In your Unix terminal, try also man fopen ... For POSIX standard, start here.
what intrigues me is the absence of the messages that I am trying to print on the screen.
That is simple. stdout is buffered (see also setvbuf(3)), and often line-buffered. So a printf which does not end with a \n has its output still inside the buffer, and not yet on the screen. The habit to get is to almost always end your printf(3) control format string with a newline, or else to flush the buffer explicitly using fflush(3).
For a newbie, there are few reasons to avoid ending your printf with an explicit \n. So use instead
printf("jkjkkjkj\n");
Otherwise, call fflush(NULL); quite often in your program. BTW, for these buffering reasons, fflush(NULL) should be done before calls to system(3), fork(2), execve(2) and other important program-wide functions.
optimized out written near the line no
That probably happens in the C standard library itself (e.g. in getc from some libc.so), which is usually not compiled with debug information. In practice, trust your C standard library: you are much more likely to have bugs in your code that in libc.
Your own source code should be compiled with gcc -Wall -Wextra -g (asking the GCC compiler to give all warnings and debug info in DWARF format, usable by the gdb debugger) and you need to improve your code to get no warnings at all before using the gdb debugger.
Be aware of undefined behavior, spend several hours reading about UB, and be scared of UB.
Try guarding against NULL in fp and for good measure make sure the debug output gets printed (as in comment by Some Programmer Dude).
#include <stdio.h>
int main(void)
{
int p , n;
FILE *fp;
printf("jkjkkjkj2\n");
fp = fopen("abc.txt","r");
if (NULL != fp)
{
while ( (n = getc(fp))!= EOF)
{
printf( "the chareacter here is %d \n", n);
}
n = fclose(fp);
} else
{
printf("File opening failed somehow!\n");
}
return 0;
}
Note the nice touch (by Basile Starynkevitch) to only close what was successfully opened.
I am learning how to write a simple CGI page with C language. I tried with Apache on both Linux and Windows. I compiled my scripts on 2 different computers that run different OSes.
Firstly, I created a simple CGI page for getting a static plain-text content:
#include
int main()
{
FILE *fp = fopen("plain_text.txt", "r"); // text-mode only.
if (fp)
{
int ch;
printf("content-type: text/plain\n\n");
while ((ch = fgetc(fp)) != EOF)
{
printf("%c", ch);
}
fclose(fp);
}
return 0;
}
I compiled it into an executable and put it in cgi-bin directory. When I browse it with my web-browser, it returns the plain-text content correctly (both Linux and Windows).
Then, I modified above script for getting a simple JPEG content.
(I understand that: every JPEG picture is a binary file)
#include
int main()
{
FILE *fp = fopen("cat_original.jpg", "rb"); // with binary-mode.
if (fp)
{
int ch;
printf("content-type: image/jpg\n\n");
while (((ch = fgetc(fp)) != EOF) || (!feof(f1))) // can read whole content of any binary file.
{
printf("%c", ch);
}
fclose(fp);
}
return 0;
}
I compiled it into an executable and put it in cgi-bin directory, too.
I can get the correct returned-image with Linux compiled-executable files; but, the Windows does not.
To understand the problem, I downloaded the returned-image with Windows compiled-execute files.
(I named this image: cat_downloaded_windows.jpg)
Then, I used VBinDiff for compare 2 images: cat_original.jpg (68,603 bytes) and cat_downloaded_windows.jpg (68,871 bytes).
There are many lines in cat_downloaded_windows.jpg (like the row I marked) have a character which cat_original.jpg does not have.
VBinDiff
So, I guess that the Windows OS causes the problem (Windows add some characters automatically, and Linux does not)
(Apache and web-browsers do not cause problem)
So, I posted this topic into StackOverflow for getting your helps. I have 2 questions:
Is there any problem with the printf("%c", ch); (in my script) on Windows?
Is there any way to print binary content into stdout, both Linux and Windows?
I am learning programming myself, and this is the first time I ask on StakOverflow.
So, if my question is not clear, please comment below this question; I will try to explain it more.
Thank you for your time!
When you use printf() to write to standard output, it is working in text mode, not binary mode, so every time your program encounters a newline \n in the JPEG file, it writes \r\n on Windows, which corrupts the JPEG file.
You'll need to know how to put standard output into binary mode and you'll need to ensure that you generate \r\n in place of \n in the headers.
The MSDN documentation says you can use _setmode(), and shows an example (setting stdin instead of stdout):
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
int main(void)
{
int result;
// Set "stdin" to have binary mode:
result = _setmode(_fileno(stdin), _O_BINARY);
if (result == -1)
perror("Cannot set mode");
else
printf("'stdin' successfully changed to binary mode\n");
}
I am conducting n simulations using a program and albeit everything being correct, there is only one mistake which I am able to see in the output files.
I am printing the outputs of the program to a csv file.
I check the file before I print to it to get it's size which if it is 0, I print the headers. Here is the function which does the same:
void Data_Output(FILE *fp, int node_num, int agg_num, int cnode, int sysdelay, int bwdth_reqt)
{
struct stat buf;
int fd = fileno(fp);
fstat(fd, &buf);
//Debug Statement
fprintf(stderr,"%d-",buf.st_size);
if (!buf.st_size) {
// Writing Headers
fprintf(fp,"Tot_Nodes_Num,Agg_Nodes_Num,Central_Node_Num,Tot_System_Delay,Bandwidth_Reqt\n");
}
// Writing Data
fprintf(fp,"%d,%d,%d,%d,%d\n",node_num,agg_num,cnode,sysdelay,bwdth_reqt);
}
For 100 simulations, the output I get from the debug shows me:
0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-
What am I doing wrong? I suspect that the program stores everything in a buffer and only prints everything to the file after it is done with the simulations and the files are closed.
Note: I open and close the files only once during the whole program and not for each simulation.
You are correct. Stdio has it's own output buffering and fstat is only concerned with logical files. So the file writes do get delayed. Try putting fflush(fp); for the last line in your Data_Output function. I hope that helps.
I'm trying to open a simple .rtf file called test in C. I'm using Xcode. My code is:
#include <stdio.h>
#include <stdlib.h>
int main (int argc, const char * argv[]) {
FILE *filePtr;
filePtr = fopen("test.rtf", "r");
if (filePtr == NULL) {
fprintf(stderr, "Can't open \"test\"\n");
exit(EXIT_FAILURE);
}
else {
printf("File open successful\n");
int x;
/* read one character at a time until EOF is reached */
while ((x = fgetc(filePtr)) != EOF) {
printf("%c", x);
}
}
fclose(filePtr);
return 0;
}
I have the test.rtf file in the same directory as my Xcode.proj directory. My output is "File open successful", however I do not get anything read from the file. Am I doing this right? Thanks.
There's nothing wrong with that code at all. I tested it (albeit not in Xcode) with a file and the transcript was:
pax> echo hello >test.rtf
pax> ./qq.exe
File open successful
hello
So the obvious think to ask is what happens when you examine test.rtf? Does it actually have any content? Because, when I do:
pax> rm test.rtf ; touch test.rtf
pax> ./qq.exe
File open successful
I get the same behaviour you observe.
Also try renaming it to test2.rtf temporarily and make sure you get the error. It's possible it may be opening a different copy of the file than what you think (this often happens in Visual C since the directory the program runs in is not always what developers think at first).
It looks right.
As for the lack of output, two possibilities:
Are you sure the file has some content? Maybe ls -l test.rtf or dir test.rft
Possibly it has some control characters which cause the terminal to which it is written to suppress output.
Try moving test.rtf to your build directory. If your project is named MyProject, move it to MyProject/build/Debug/.
I can think of two things that could cause this problem. Either there is an error when calling fgetc, or you are getting output that you don't recognize.
fgetc() will return EOF when the end of the file is reached, or an error occurs. To determine if it's an error, just after your while loop try:
if (ferror(filePtr) != 0) printf("error: %d.\n", errno);
A .rtf file is not a plain text file. It likely contains a bunch of formatting information. You are expecting to see "Hello . . . ". but what you may actually see is something like:
{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf250
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\margl1440\margr1440\vieww9000\viewh8400\viewkind0
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040
\f0\fs24 \cf0 Hello . . .
And you are just assuming that is GDB output, not your program's output.
Based upon your recent comments, I think you have an empty file test.rtf in the directory your program is run in, and your real test.rtf file is in some other directory. Maybe your fopen() call at some point was fopen("test.rtf", "w"); instead of fopen("test.rtf", "r");, and you later modified it.
To see the directory your program is running in, add the following to your program after the FILE *filePtr; line:
char pwd[512];
if (getcwd(pwd, sizeof pwd) != -1)
printf("In directory %s\n", pwd);
else
fprintf(stderr, "Need bigger buffer, change '512' above\n");
Then, you can open a terminal, do cd <directory>, and test for yourself if the file you want is the file your program is opening.
You probably want this file to be plain text, not rich text. Rich text has a lot of formatting encoded into the file.