tags:

views:

74

answers:

2

I am trying to write a database for class in which I read all the key values in from a file (formatted keyNULL BYTEvalueNULL BYTE etc). I amt rying to use a linked list for this, but I get the error that the struct has no next value. Please help me!

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdbool.h>

#include "sdbm.h"

static FILE *db;
static bool opened = false;
static int err = 0, keyLen = 8;

typedef struct {
  char *name;
  Key *next;
} Key;

static Key *head = NULL,*tail = NULL; 
/**
 * Create new database with given name. You still have
 * to sdbm_open() the database to access it. Return true
 * on success, false on failure.
 */
bool sdbm_create( const char *name ) { //Errors: 1) fopen failed 2) fclose failed on new db
  db = fopen(name, "w");
  if (db == NULL) {
    printf("Couldn't create file %s\n",name);
    err = 1;
    return false;
  }
  if (fclose(db) == EOF) {
    printf("Couldn't close created file %s\n",name);
    err = 2;
    return false;
  }
  return true;
}
/**
 * Open existing database with given name. Return true on
 * success, false on failure.
 */
bool sdbm_open( const char *name ) { //Errors: 3) couldn't open database
  db = fopen(name,"r+");
  if (db == NULL) {
    err = 3;
    printf("Couldn't open database file %s\n",name);
    return false;
  }
  opened = true;
  int c;
  bool inKey = true;
  int currKey[MAX_KEY_LENGTH];
  while ((c = getc(db)) != EOF)  {
    if (!inKey && c == '\0') {
      inKey = true;
    }
    else if (inKey && c == '\0') {
      if (tail != NULL) {
        tail->next = malloc(sizeof(Key));
        tail = tail->next;
      }
      else {
        tail = malloc(sizeof(Key));
        head = tail;
      }
      tail->next = NULL;
      tail->name = currKey;

    }
    else if (inKey) { 
      currKey[keyLen] = c;
      keyLen++;
    }
  }
}
/**
 * Synchronize all changes in database (if any) to disk.
 * Useful if implementation caches intermediate results
 * in memory instead of writing them to disk directly.
 * Return true on success, false on failure.
 */
//bool sdbm_sync();

/**
 * Close database, synchronizing changes (if any). Return
 * true on success, false on failure.
 */
bool sdbm_close() { // Errors: 5) Couldn't close database
  if (fclose(db) == EOF) {
    err = 5;
    printf("Couldn't close database.\n");
    return false;
  }
  return true;
}
/**
 * Return error code for last failed database operation.
 */
int sdbm_error() {
  return err;
}

/**
 * Is given key in database?
 */
//bool sdbm_has( const char *key );

/**
 * Get value associated with given key in database.
 * Return true on success, false on failure.
 *
 * Precondition: sdbm_has(key)
 */
//bool sdbm_get( const char *key, char *value );

/**
 * Update value associated with given key in database
 * to given value. Return true on success, false on
 * failure.
 *
 * Precondition: sdbm_has(key)
 */
//bool sdbm_put( const char *key, const char *value );

/**
 * Insert given key and value into database as a new
 * association. Return true on success, false on
 * failure.
 *
 * Precondition: !sdbm_has(key)
 */
//bool sdbm_insert( const char *key, const char *value );

/**
 * Remove given key and associated value from database.
 * Return true on success, false on failure.
 *
 * Precondition: sdbm_has(key)
 */
//bool sdbm_remove( const char *key );
+2  A: 

While I'm digging my compiler out, can you try changing the declarations to:

typedef struct Key_ {
  char *name;
  struct Key_ *next;
} Key;

and let us know if that helps? I think you may be using the typedef before it's declared.

jwismar
My compiler didn't complain about that either way - with the struct tag name, or with the typedef, either way was fine. It did complain about a couple of void* casts, and that currKey was an array of int and couldn't be assigned to a pointer to char.
jwismar
You can use the same name, no need for an underscore suffix.
Roger Pate
Fair enough. It runs in my mind that there's some issue either with an old standard, or with cross-compatibility with C++, where having the struct tag name collide with the typedef was an issue, so when I'm writing C, I tend to use this style. It may be out of date.
jwismar
Possibly with *really* old compilers, but standard C++ lets you typedef a name to the same name. (E.g. even `struct A {}; typedef A A;` is valid.)
Roger Pate
+7  A: 

The definition should be like

typedef struct Key{
  char *name;
  struct Key *next; // <-- Note `struct` here
}Key;

You cannot use just Key[without explicitly writing struct before it] inside the definition of the structure because the structure is not yet defined [typedefed]

Prasoon Saurav
You're the best. It works now. Can't wait until I know C and don't make these kinds of mistakes.
David Watson
One question, does this change the type of next? Is it now a struct Key * or is it still just a Key *?
David Watson
@David Watson : It is a `struct Key*`. `typdef` is just used as a placeholder/synonym for another type.
Prasoon Saurav
@David: After the typedef, 'struct Key' and 'Key' mean the same thing. If you missed the distinction, within the struct definition is *before* the typedef takes affect, so there you need 'struct Key'.
Roger Pate
@Prasoon: I'm not sure leaving out the struct name (in the first line) is valid C; though as you have it, gcc accepts line 3 (actually, gcc accepts *any* name on line 3, but incorrect names produce invalid debug info).
Roger Pate
This answer is *incorrect* unless you replace `typedef struct {` with `typedef struct Key {`. As it stands, you're declaring a pointer to an incomplete type `struct Key` which is never completed, not a pointer to type `Key` (which is `typedef`'d to an anonymous `struct`).
R..