Re: Stack with file access?.

From: ritchie (ritchie_s01_at_yahoo.com)
Date: 03/27/04


Date: 27 Mar 2004 11:44:59 -0800

Jens.Toerring@physik.fu-berlin.de wrote in message news:<c445o0$2doua1$1@uni-berlin.de>...
> ritchie <ritchie_s01@yahoo.com> wrote:
> > I have modified my two functions (below).
>
> > The "writeStack" function now loops the stack, writing each node to
> > file.
> > I think that I have this correct so far?
>
> > The "readStack" function now reads the file and creates a new node for
> > the first record.
> > My question here is, how could I modify my code to get this function
> > to read the entire file, creating a new node for each record?
> > I have tried this a number of ways but I keep ending up with just the
> > first record from the file or else an infinite loop.
>
> > Any suggestions would be great.
>
> > Thanks again to all,
> > Ritchie.
>
> > /*~~~~~~~~~ write / read stack functions ~~~~~~~~~~~~~~*/
> > /* write full stack to file */
> > void writeStack ( NodePtr ptr )
> > {
> > FILE * fPtr; /* file pointer */
> > if ((fPtr = fopen("file.dat", "wb")) == NULL) /*create binary
> > file*/
> > puts("Error?..");
> > else
> > {
> > while ( ptr != NULL ) /* loop to write full stack */
> > {
> > fwrite( ptr, sizeof(*ptr), 1, fPtr); /*write stack */
> > ptr = ptr->nextPtr; /* move to next node */
> > }
> fclose( fPtr); /* close file */
> > }
>
> > /* read file into stack */
> > void readStack ( NodePtr *ptr )
>
> You might think about having the function return the pointer instead
> of passing it a double pointer...
>
> > {
> > Node newPtr = malloc( sizeof( Node ) ); /* create new node for file
> > data*/
>
> You need to check if malloc() did succeed and you allso will need to do
> allocation within the loop.
>
> > FILE *fInPtr; /* file pointer */
> >
> > if ((fInPtr = fopen("orders.dat", "rb")) == NULL)
> ^^^^^^^^^^
>
> You're reading from "orders.dat" here but wrote to "file.dat".
>
> > {
> > fprintf(stderr, "\n\nCannot open %s\n", "file.dat");
> > }
>
> You must return if you can't open the file...
>
> > /* read into new node?*/
> > if( ( fread (newPtr, sizeof(*newPtr), 1, fInPtr)) != 1)
> > printf("error??\n");
> >
> > if (newPtr == NULL)
> > {
> > puts("error....");
> > }
> > else
> > {
> > puts("Details:");
> > printf( "ID: %d \n", newPtr-> stackID);
> > printf( "ID: %d \n", newPtr-> stackName);
> >
> > newPtr->nextPtr = *ptr; /* point to next node ? */
> > *ptr = newPtr;
> > }
> fclose(fInPtr);
> > }
> > /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ END ~~~~~~~~~~~~~~*/
>
> Here's an (untested) version of your read routine - I didn't use your
> NodePtr type because I don't like to hide the pointer-ness of a variable.
> If the function returns NULL (instead of the first element of your
> list) it indicates that either an error happened or that there were
> no elements to be read.
>
> Node *readStack( const char *file_name )
> {
> FILE *fInPtr;
> Node *head;
> Node *new_ptr;
> Node *prev_ptr;
>
> if ( ( fInPtr = fopen( file_name, "rb" ) ) == NULL )
> {
> fprintf( stderr, "Can't open file '%s' for reading\n", file_name );
> return NULL;
> }
>
> if ( ( head = malloc( sizeof *head ) ) == NULL )
> {
> fprintf( stderr, "Running out of memory\n" );
> fclose( fInPtr );
> return NULL;
> }
>
> for ( new_ptr = head;
> fread ( new_ptr, sizeof *new_ptr, 1, fInPtr ) ) == 1;
> new_ptr = new_ptr->NextPtr )
> {
> printf( "ID: %d\n", new_ptr->stackID );
> printf( "ID: %d\n", new_ptr->stackName );
>
> if ( ( new_ptr->nextPtr = malloc( sizeof *new_ptr ) ) == NULL )
> {
> fprintf( stderr, "Running out of memory\n" );
>
> fclose( fInPtr );
>
> while ( head != NULL )
> {
> new_ptr = head;
> head = head->NextPtr;
> free( new_ptr );
> }
>
> return NULL;
> }
>
> prev_ptr = new_ptr; /* needed to get rid of the last, unused element */
> }
>
> fclose( fInPtr );
>
> if ( new_ptr == head ) /* no elements could be read */
> head = NULL;
> else /* last allocated element isn't used */
> prev_ptr->NextPtr = NULL;
>
> free( new_ptr );
>
> return head;
> }
> Regards, Jens

Hi,

Thanks to everyone who has replied to my posts.

As suggested, I have taken out the typedef's for my pointer and it is
much clearer, thanks.
I also read up more on files and now just open the file once, ("ab+"),
in main and pass the file pointer to each function.
I believe this incurs less overhead, rather than opening and closing
the file in each function.

I also wanted to try to modify the file.
I tried a million and one ways, but couldn't get it right.
I have tested this out on another small program with just integers and
it worked fine.

I thought that this would entail something like:
1: point file pointer to BOF
2: create new node to read value into /* is this needed? */
3: Loop/Read file & search for record to be modified
4: If value is found, get new value & update record

Am I correct about this algorithm?
If not, can anybody see where I have gone wrong and maybe point me in
the
right direction?

I have included a very basic (no error checking yet) attempt at this
below. The problem here is, a new node is created and written to
file, but not modifing the
specified file value.

Thanks again for taking the time,
Ritchie

/******************* one of my attempts at this *********************/
struct node{
  int stackID;
  int stackName;
  struct node * nextPtr;
};
typedef struct node Node;

....
/*** update a binary file function ***/
/*** params: pointer to pointer to top of stack ****/
/*** iD: value to update, I/O [binary] file pointer ****/
int updateFile(Node **topPtr, int iD, FILE *fIn )
{
  rewind( fIn ); /* rewind the file to BOF for read */

  while (!feof(fIn)){ /* loop to EOF */
    Node *newPtr = malloc( sizeof( Node ) );/* create new node to read
into */

    fread (newPtr, sizeof(*newPtr), 1, fIn );
  /* fseek( fIn, 0L, SEEK_CUR ); ???? */
                        
    if( newPtr->iNodeID == iD ) /* if value entered is found */
    {
        puts("Record found");
        printf( "Record: %d \n", newPtr->iNodeID ); /* display it */

        puts("Enter new value: ");
        scanf("%d", &newPtr->iNewVal ); /* get new value */
        fwrite( newPtr->iHeight, sizeof(*newPtr), 1, fIn ); /* write new
value */
    }
    
        }
   return 0;
}



Relevant Pages

  • LinkedList Pointer (REPOST - diff version)
    ... struct node * next; ... No problem until you are dealing with a pointer variable. ... void Push(struct node** headRef, int newData); ... Given an int and a reference to the head pointer (i.e. a struct ...
    (comp.lang.c)
  • LinkedList Pointer (REPOST - diff version)
    ... struct node * next; ... No problem until you are dealing with a pointer variable. ... void Push(struct node** headRef, int newData); ... Given an int and a reference to the head pointer (i.e. a struct ...
    (comp.lang.c)
  • Re: Pointers
    ... Explicit pointer types serve the following purposes in C: ... void swap(int a, int b) ... The dynamic memory allocation functions, calloc, etc.) ... struct node *left; ...
    (comp.lang.c)
  • creating linked list
    ... -1 to exit. ... int item; ... // returns a pointer to a linked list containing those integers, ...
    (comp.lang.cpp)
  • Re: LinkedList Pointer (REPOST - diff version)
    ... > Here's the original problem. ... > struct node * next; ... > No problem until you are dealing with a pointer variable. ... > node** pointer to the head pointer), add a new node at the head of the ...
    (comp.lang.c)