C Board  

Go Back   C Board > General Programming Boards > C Programming

Reply
 
LinkBack Thread Tools Display Modes
Old 07-05-2009, 06:06 PM   #1
Registered User
 
Tigers!'s Avatar
 
Join Date: Jun 2009
Location: Melbourne, Australia
Posts: 49
NULL or '\o' usage

Gudday all
I am a little puzzled by the NULL or \0 that terminates strings and how is it generated and tested for.
I am reading in a list of file names as the contents of a file (file A) . I then wish to open File A and use it's contents to open the text files in question and analyse them.
The problem I have is that I can open file A ok and print out its contents but I can't seem to open the individual files and print their contents.
I am want to read out their contents line by line and print them for a start. I am using a NULL check to get the whole line but it seems to be ignored
Code:
while (fgets(fileline, 22, tmpFile)!=NULL) {
				printf("*** Inside the RPT file contents ***\n");
The generation of File A is
Code:
intptr_t searchHandle = _findfirst("*.rpt", &fileData);
	// if the search started
	if (searchHandle != -1) {
		// print a banner
		//puts("Found the following files:");
		rptFile = fopen (rpt_file, "w+");  /* open data file "rptFile.dat" for writing */
		do {
			// print the file name
			//puts(fileData.name);
			fprintf(rptFile, "%s\n", fileData.name);  /* write RPT file name to rptFile.dat file  */
		}
		// look for any more files
		while (_findnext(searchHandle, &fileData) == 0);
		// stop the search after all have been enumerated
		_findclose(searchHandle);
		fclose(rptFile);
The contents of file A have the form 20090220085501237.RPT which is 21 characters. I have allowed 22 characters for the fgets to have the \0 included. Is the \0 automatically included when the line is added to File A? Do I have to included it separately? Is NULL the best check?

The opening of file A is
Code:
if ( (access(rpt_file, F_OK)) != -1 ) {
		//printf("An RPT.dat file exists\n");
		rptFile = fopen (rpt_file, "r");
		while (fgets(rptline, 25, rptFile)!=NULL) { //loop for reading a line up to end of file
			//printf("RPT file exists, getting name of it out of file\n");
			printf("%s", rptline); //print the name of each RPT file found
			printf(" Opening %s", rptline);
			//open each RPT individually and print out it's contents.
			tmpFile = fopen(rptline, "r"); /* open data file "rptFile.dat" for reading */
			while (fgets(fileline, 22, tmpFile)!=NULL) {
				printf("*** Inside the RPT file contents ***\n");
			}
			printf(" Closing %s", rptline);
			fclose(tmpFile);
		}


	} else {
		printf("An RPT.dat file does not exist");
		return 0;
	}
(I do hope my request is clear enough)
Tigers! is offline   Reply With Quote
Old 07-05-2009, 07:23 PM   #2
and the Hat of Guessing
 
tabstop's Avatar
 
Join Date: Nov 2007
Posts: 8,740
1. A pointer can be NULL. A character can be '\0'.

2. To be a string, a bunch of characters in memory must have a '\0' character at the end. This character is neither read from or written to a file. (But when a string is read in, the '\0' character is (almost always) added to the end for you.)
tabstop is offline   Reply With Quote
Old 07-05-2009, 07:32 PM   #3
Registered User
 
Join Date: Sep 2006
Posts: 2,415
Using != NULL: I would use != EOF, instead. Your while loop is getting all the lines in the file, not just the first line. Don't worry, fgets() knows to stop whenever it encounters a newline.


For your buffer, I would make it one to two chars longer - there will be a newline (which may be actually two char's for a Windows text file (CarriageReturn&LineFeed).

All of these input details can be readily solved by checking the contents of your buffer, and the contents of your line of text.

Another check - when you print your buffer, does it move the cursor down to the next line and return it to the far left hand side of the screen? If so, then you know it has the newline char in it.

Same goes with your filenames. Print them out. Remember that a \ char is an escape char in printf(). You need two \\'s to show one \ with printf().

It's not '\o', it's '\0' for the end of string char.
Adak is offline   Reply With Quote
Old 07-05-2009, 10:26 PM   #4
Registered User
 
Tigers!'s Avatar
 
Join Date: Jun 2009
Location: Melbourne, Australia
Posts: 49
Thank you for your replies.
I am still having trouble so I added in a test message to see if I am opening each file mentioned in File A correctly.
Code:
if(tmpFile==NULL) {
  printf("Error: can't open file.\n");
  return 1;
}
I am getting the error message (see attachment) which I assume tells me that I am not opening any file given in File A correctly. The file name is being read correctly from File A as I can print it out and it is correct.
I am opening the file, denoted by rptline, as read only e.g.
Code:
tmpFile = fopen(rptline, "r"); /* open data file "rptFile.dat" for reading */
rptline is a character string that has been previously read in from file A
Code:
char rptline[25];   //name of RPT file
..
while (fgets(rptline, 25, rptFile)!=NULL)
{
..
}
I am getting no compiler errors or warnings but is it permissible (or wise) to pass the file name into fopen as I have been doing as shown below?
Code:
tmpFile = fopen(rptline, "r"); /* open data file "rptFile.dat" for reading */
Maybe I am not setting up fopen correctly?
It may not be a subtle error as I am still relearning C and have had blatant errors in the past.
Attached Images
 
Tigers! is offline   Reply With Quote
Old 07-05-2009, 10:29 PM   #5
and the hat of vanishing
 
Salem's Avatar
 
Join Date: Aug 2001
Location: The edge of the known universe
Posts: 21,214
> I have allowed 22 characters for the fgets to have the \0 included.
So where did 25 come from?
fgets(rptline, 25, rptFile)

If you've got
char rptline[22];
then
fgets(rptline, sizeof(rptline), rptFile)
is the best way of making sure the size passed to fgets() is correct.


> Using != NULL: I would use != EOF, instead.
Except fgets() doesn't return EOF, it returns NULL

Edit: answer to your update
Having read a line using fgets(), you need to remove the \n from the end before using it as a filename.
How to do this is in the FAQ somewhere.
__________________
If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
Up to 8Mb PlusNet broadband from only £5.99 a month!
Salem is offline   Reply With Quote
Old 07-05-2009, 10:49 PM   #6
Registered User
 
Join Date: Oct 2008
Location: TX
Posts: 1,238
Strip out the newline left behind as your buffer (rptline[]) is bigger than the string you are reading from fileA, as in
Code:
while (fgets(rptline, 25, rptFile)!=NULL)
    rptline[strlen(rptline)-1] = NULL;
    ...
itCbitC is offline   Reply With Quote
Old 07-05-2009, 11:06 PM   #7
and the hat of vanishing
 
Salem's Avatar
 
Join Date: Aug 2001
Location: The edge of the known universe
Posts: 21,214
> rptline[strlen(rptline)-1] = NULL;
Whilst NULL may be 0 on your system, it sends the wrong semantic message to the reader. Use '\0' when referring to the character called 'nul'.

Also, simply removing the last character does NOT take into account the case where there is no \n at the end (for example, reading a long line into a short buffer).
__________________
If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
Up to 8Mb PlusNet broadband from only £5.99 a month!
Salem is offline   Reply With Quote
Old 07-06-2009, 04:16 AM   #8
Registered User
 
Join Date: Sep 2006
Posts: 2,415
This is one way to do it:

To see it work, you'll need at least 2 tiny files: (I tested it with 4)

1) filenames.txt - which just lists each of the below listed filenames, one per line.

2) files with the proper names and extensions (if any), that you have listed in #1, above.
Each of these files should have 1 single integer on the first line, and nothing else.

The trick mentioned by itCbitzC above, is worth remembering when you're working with strings:
Code:
 fnames[strlen(fnames)-1] = '\0';

Code:
/*Snippet shows how to read a list of files, and then open each file, one
after the other.

Status: OK
*/

#include <stdio.h>
#include <string.h>

int main(void)  {
  int i, number;
  FILE *in1, *in2;
  char fnames[25];

  /*Earlier I said use EOF for this test - 
    that was wrong ( EOF is used with fscanf() ),
    use NULL for fopen() and fgets() testing.
  */
  //Open the file with the filenames listed in them
  if((in1=fopen("filename.txt", "rt")) == NULL)  {
     printf("\nError opening filename.txt, program terminated\n");
     return 1;
  }
  /*read a filename, and open that file. Read it's contents, and close it
    when all it's data has been read. Then repeat on each subsequent file 
    that's listed.
  */
  printf("\n\n");
  while(fgets(fnames, 23, in1) != NULL) {
     fnames[strlen(fnames)-1] = '\0';

     if((in2 = fopen(fnames, "rt")) == NULL)  {
        printf("\nFile Not Found: %s\n", fnames);
        continue;
     }
     if(fscanf(in2, "%d", &number))
        printf("\n The number I read was: %d", number);

     close(in2);
     for(i = 0; i < 25; i++)
        fnames[i] = '\0';
  }

  close(in1);
  printf("\n\n\t\t\t     Press Enter When Ready");
  i = getchar();
  return 0;

}
If one filename that is listed doesn't open, the subsequent files may still be opened.

Last edited by Adak; 07-06-2009 at 10:48 AM.
Adak is offline   Reply With Quote
Old 07-06-2009, 10:02 AM   #9
Registered User
 
Join Date: Oct 2008
Location: TX
Posts: 1,238
Quote:
Originally Posted by Salem View Post
> rptline[strlen(rptline)-1] = NULL;
Whilst NULL may be 0 on your system, it sends the wrong semantic message to the reader. Use '\0' when referring to the character called 'nul'.
ITA as that is a symbolic constant used mainly for NULL pointers instead of char or int types.
Quote:
Originally Posted by Salem View Post
Also, simply removing the last character does NOT take into account the case where there is no \n at the end (for example, reading a long line into a short buffer).
You're right, my solution was specific given that the string read from fileA was shorter (=21) than the destination buffer (=22).
itCbitC is offline   Reply With Quote
Old 07-06-2009, 04:46 PM   #10
Registered User
 
Tigers!'s Avatar
 
Join Date: Jun 2009
Location: Melbourne, Australia
Posts: 49
Et al
Thank you for all your replies.
Having a fiddle last night I could get File A to be read provided it was created in the form
Code:
20090220085501237.RPT20090310111500094.RPT20090316112501203.RPT20090507091000206.RPT20090604103500072.RPT
That is, all the desired file names are in a long string. Of course I had to make sure that the no. of characters taken by fgets was correct at 22

Is it possible to be able to get File A to be created in the form
Code:
20090220085501237.RPT
20090310111500094.RPT
20090316112501203.RPT
20090507091000206.RPT
20090604103500072.RPT
and still be able to be read by fgets?
I am still unsure whether '\0' needs to be added by my programme when creating file A and whether I need to add '\n' (new line or carriage return).
Are the '\0' and '\n' considered as part of the characters that fgets must extract or can they be ignored?

Or maybe I just start again?
Tigers! is offline   Reply With Quote
Old 07-06-2009, 04:57 PM   #11
subminimalist
 
MK27's Avatar
 
Join Date: Jul 2008
Location: NYC
Posts: 3,788
Quote:
Originally Posted by Tigers! View Post
I am still unsure whether '\0' needs to be added by my programme when creating file A and whether I need to add '\n' (new line or carriage return).
Are the '\0' and '\n' considered as part of the characters that fgets must extract or can they be ignored?
You should not be writing '\0' to a file unless you have some particular (unusual) reason to do so, but you do need to use '\n'.

fgets() reads to the newline, chucks it, and adds a null terminator, so you do not have to deal explicitly with either character in an fgets statement.

Your suggested format for file A should be fine, but you will need to add a \n to get the filenames on separate lines. WRT to that, this is a valid string:

Code:
"20090220085501237.RPT\n20090310111500094.RPT\n20090316112501203.RPT\n"
__________________

Accuracy and integrity mean nothing if you don't make it past the censors...PYTHAGORAS

Last edited by MK27; 07-06-2009 at 05:00 PM.
MK27 is offline   Reply With Quote
Old 07-06-2009, 05:01 PM   #12
Registered User
 
Join Date: Apr 2006
Location: United States
Posts: 3,183
There's information regarding replacing '\n' with '\0' here. If you use a flexible approach like the one from the link, the format of the file names file won't matter so much, as long as the input from fgets is going to be complete (hence I think why you want to read 25 characters, as every file name is this size in the file -- give that constant a name, btw!).
__________________
Os iusti meditabitur sapientiam
Et lingua eius loquetur indicium

"There is nothing either good or bad, but thinking makes it so." (Shakespeare, Hamlet, Act II scene ii)

http://www.myspace.com/whiteflags99
whiteflags is offline   Reply With Quote
Old 07-06-2009, 05:19 PM   #13
Senior software engineer
 
brewbuck's Avatar
 
Join Date: Mar 2007
Location: Portland, OR
Posts: 5,357
Quote:
Originally Posted by MK27 View Post
You should not be writing '\0' to a file unless you have some particular (unusual) reason to do so, but you do need to use '\n'.
I don't see why '\0' is different from any other character as far as writing/reading a file. If you wanted to write a string to a file and that string contained embedded '\n' characters then obviously you'd need some other way of telling where the end of the string was. You could do that by specifying the number of characters explicitly, or by using null termination.

If the output of your program is considered "text" then it probably should not contain null characters, but "text" is not the only kind of output a program could produce.
__________________
"Congratulations on your purchase. To begin using your quantum computer, set the power switch to both off and on simultaneously." -- raftpeople@slashdot
brewbuck is offline   Reply With Quote
Old 07-06-2009, 05:29 PM   #14
subminimalist
 
MK27's Avatar
 
Join Date: Jul 2008
Location: NYC
Posts: 3,788
Quote:
Originally Posted by brewbuck View Post
If the output of your program is considered "text" then it probably should not contain null characters, but "text" is not the only kind of output a program could produce.
Considering this file contains "text", it is probably meant to be used in the normal ways a text file might be used. If you stick zero bytes in it, that will foul up the "normal" operation of fgets() & friends.

But there is no law, human or otherwise, that says you cannot do that.
__________________

Accuracy and integrity mean nothing if you don't make it past the censors...PYTHAGORAS
MK27 is offline   Reply With Quote
Old 07-06-2009, 05:43 PM   #15
Senior software engineer
 
brewbuck's Avatar
 
Join Date: Mar 2007
Location: Portland, OR
Posts: 5,357
Quote:
Originally Posted by MK27 View Post
Considering this file contains "text", it is probably meant to be used in the normal ways a text file might be used. If you stick zero bytes in it, that will foul up the "normal" operation of fgets() & friends.
No it won't. fgets() pays no attention to '\0'. It reads bytes until it either fills the buffer or sees a '\n'
__________________
"Congratulations on your purchase. To begin using your quantum computer, set the power switch to both off and on simultaneously." -- raftpeople@slashdot
brewbuck is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Linked List Not Saving Value as Int bar338 C Programming 4 05-04-2009 07:53 PM
Help Debugging my AVL tree program. Nextstopearth C Programming 2 04-04-2009 01:48 AM
Compiling 3rd party code problem me too siavoshkc C Programming 1 09-12-2007 05:55 AM
Linked List of Linked list of linked list : problem with a condtion gemini_shooter C Programming 6 03-02-2005 02:45 AM
Contest Results - May 27, 2002 ygfperson A Brief History of Cprogramming.com 18 06-18-2002 01:27 PM


All times are GMT -6. The time now is 01:17 PM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.0 RC2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22