Dekko.Delanforrings Dekko.Delanforrings - 3 months ago 7
C Question

Why does my code read nothing from input?

My code is expected to read input like a string "Mr Hoagie", "Yishan" and etc. or a keyfile which has one string on one line.
The input data file is a type .csv file.
The desire output should look like:

– output file (information):

Mr Hoagie -- > city: Dravosburg || review count: 4 || name: Mr Hoagie || type: business|| full address: 4734 Lebanon Church Rd Dravosburg PA 15034 || hours: Tuesday close 21 00open 11 00 Friday close 21 00 open 11 00 Monday close 21 00 open 11 00 Wednesday close 21 00open 11 00 Thursday close 21 00 open 11 00 || state: PA || longitude: 79 9007057 || stars:4 5 || latitude: 40 3543266 || attributes: Take out True Drive Thru False Outdoor SeatingFalse Caters False Noise Level average Parking garage False street False validated False lot
False valet False Delivery False Attire casual Has TV False Price Range 1 Good For dessert Falselatenight False lunch False dinner False breakfast False brunch False Takes Reservations FalseAmbience romantic False intimate False classy False hipster False divey False touristy False trendy False upscale False casual False Waiter Service False Accepts Credit Cards True Good for Kids True Good For Groups True Alcohol none || open: True || categories: Fast Food Restaurants
||

Yishan -- > yelping since: 2004 10 || votes: funny 44 useful 48 cool 19 || name: Yishan || type: user || compliments: cute 2 funny 1 plain 1 writer 1 note 1 cool 1 more 1 || fans: 8 || average stars: 3 82 || review count: 45 ||

Nir Lipo Hotel -- > NOTFOUND

– stdout (comparisons):

Mr Hoagie -- > 423

Spicy Tang -- > 230

Nir Lipo Hotel -- > 401

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


#define MAXNAMELENTH 64
#define MAXDATALENTH 1465

typedef struct node
{
char name[MAXNAMELENTH];
char data[MAXDATALENTH];
struct node* left;
struct node* right;
}node;

node* root;
node* search(node ** tree, char *key, int count, FILE *fp_out);
int insertion(node** r, char *key, char *value);
void deltree(node * tree);
void trim(char* source);


int main(int argc, char *argv[])
{
node *root;
FILE *fp;
FILE *outputfile;
int res;
int counter = 0;
int bufsize = MAXDATALENTH + MAXNAMELENTH + 2;
char *buffer;
char *keyin = NULL;
char *valuein = NULL;
char *input;
char *comma;
char *point;


root = NULL;

// must have at least one argument
if (argc < 2) {
fprintf(stderr, "Usage: %s datafile [< key-list]\n", argv[0]);
exit(EXIT_FAILURE);
}

/* Inserting nodes into tree */
buffer = malloc(bufsize);
if (buffer == NULL) {
fprintf(stderr, "Malloc failed\n");
exit(EXIT_FAILURE);
}

fp = fopen(argv[1], "r");
if (fp == NULL) {
fprintf(stderr, "Opening \"%s\" for reading failed\n", argv[1]);
exit(EXIT_FAILURE);
}

outputfile = fopen("outputfile.txt", "a");
if (fp == NULL) {
fprintf(stderr, "Opening \"outputfile.txt\" for appending failed\n");
exit(EXIT_FAILURE);
}

while ((input = fgets(buffer, bufsize, fp))) {

if (input == NULL) {
if (ferror(fp)) {
// TODO: check errno for the exact kind of error
fprintf(stderr, "An eror occured during reading \"%s\"\n", argv[1]);
exit(EXIT_FAILURE);
}
else if (feof(fp)) {
break;
}
}
// assuming strict KEY","DATA"\n" and without whitespace

// valuein points to the comma before DATA
valuein = strchr(buffer, ',');
// valuein points to DATA
if ((point = strchr(valuein, '\n')) != NULL)
*point = '\0';
// comma points to the comma before DATA
comma = strchr(buffer, ',');
// make *comma NUL
*comma = '\0';
keyin = buffer;
// ignoring return for now
//printf("%s,%s\n",keyin, valuein);
(void)insertion(&root, keyin, valuein);
}


/* Search node into tree */
// search-keys come from either stdin or get typed in.
// things typed in are also stdin
while ((res = scanf("%s", buffer)) == 1) {
trim(buffer);
if (strcmp(buffer, "exit")== 0) {
exit(0);
}
search(&root, buffer, counter, outputfile);
counter = 0;
}


/* Deleting all nodes of tree */
deltree(root);

fclose(fp);
fclose(outputfile);
return 0;
}


void trim(char* source)
{
char* i = source;
char* j = source;
while (*j != 0)
{
*i = *j++;
if (*i != ' ')
i++;
}
*i = 0;
}



int insertion(node** r, char *key, char *value)
{
if (*r == NULL) {
*r = malloc(sizeof(node));
if (r == NULL) {
return 0;
}
strcpy((*r)->name, key);
strcpy((*r)->data, value);

(*r)->left = NULL;
(*r)->right = NULL;
}
// Checks for returns omitted for clarity
else if (strcmp(key, (*r)->name) < 0) {
insertion(&(*r)->left, key, value);
}
// else this will be in the right subtree
else if (strcmp(key, (*r)->name) > 0) {
insertion(&(*r)->right, key, value);
}
else {
if (strcmp(value, (*r)->data) > 0) {
insertion(&(*r)->left, key, value);
}
else if (strcmp(value, (*r)->data) < 0) {
insertion(&(*r)->right, key, value);
}
return 0;
}

return 1;
}

void
deltree(node * tree) {
if (tree) {
deltree(tree->left);
deltree(tree->right);
free(tree);
}
}

node *search(node ** tree, char *key, int count, FILE * fp_out)
{
node *tmp;
if (!(*tree)) {
printf("%s --> %d\n", key, count);
fprintf(fp_out, "%s --> NOTFOUND", key);
return NULL;
}
else {
if (strcmp(key, (*tree)->name) < 0) {
tmp = search(&(*tree)->left, key, count, fp_out);
count++;
return tmp;
}
else if (strcmp(key, (*tree)->name) > 0) {
tmp = search(&(*tree)->right, key, count, fp_out);
count++;
return tmp;
}
else {
printf("%s --> %d\n", key, count);
return *tree;
}
}
}

Answer

You could have debugged it yourself, I'm pretty sure, but as I started it I have to end it, too, I think ;-)

It can be quite tedious to hit n a thousand times or more if you want to step through a program processing large data. In that case (and others, maybe) it is better to use some kind of print and inspect it visually or with grep or Perl or whatever comes handy.

I added something in the code to show the principle.

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

#ifdef DEBUG
#define PRINT(x) puts(x)
#else
#define PRINT(x)
#endif

#define MAXNAMELENTH 64
#define MAXDATALENTH 1465

typedef struct node
{
    char name[MAXNAMELENTH];
    char data[MAXDATALENTH];
    struct node* left;
    struct node* right;
}node;

node* root;
node* search(node ** tree, char *key, int count, FILE *fp_out);
int insertion(node** r, char *key, char *value);
void bt_print(node * leaf);
void deltree(node * tree);
void trim(char* source);
#if !(defined _POSIX_C_SOURCE) || _POSIX_C_SOURCE < 200809L
#include <sys/types.h>
ssize_t getline(char **pline_buf, size_t *pn, FILE *fin);
#endif

int main(int argc, char *argv[])
{
    node *root;
    FILE *fp;
    FILE *outputfile;
    int res;
    int counter = 0;
    int bufsize = MAXDATALENTH + MAXNAMELENTH + 2;
    char *buffer;
    char *keyin = NULL;
    char *valuein = NULL;
    char *input;
    char *comma;
    char *point;

    char *line_buf = NULL;
    size_t line_buf_size = 0;
    ssize_t line_size;

    root = NULL;

    // must have at least one argument
    if (argc < 2) {
        fprintf(stderr, "Usage: %s datafile [< key-list]\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    /* Inserting nodes into tree */
    buffer = malloc(bufsize);
    if (buffer == NULL) {
        fprintf(stderr, "Malloc failed\n");
        exit(EXIT_FAILURE);
    }

    fp = fopen(argv[1], "r");
    if (fp == NULL) {
        fprintf(stderr, "Opening \"%s\" for reading failed\n", argv[1]);
        exit(EXIT_FAILURE);
    }

    outputfile = fopen("outputfile.txt", "a");
    if (fp == NULL) {
        fprintf(stderr, "Opening \"outputfile.txt\" for appending failed\n");
        exit(EXIT_FAILURE);
    }

    while ( (line_size = getline(&line_buf, &line_buf_size, fp)) > 0 ) {
            if (ferror(fp)) {
                // TODO: check errno for the exact kind of error
                fprintf(stderr, "An eror occured during reading \"%s\"\n", argv[1]);
                exit(EXIT_FAILURE);
            }
            else if (feof(fp)) {
                break;
            }
        // assuming strict KEY","DATA"\n" and without whitespace

        //TODO: check if line_size < bufsize!

        // valuein points to the comma before DATA
        valuein = strchr(line_buf, ',');
        // skip comma
        valuein++;
        // valuein points to DATA now
        // might have no new line at the end
        if ((point = strchr(valuein, '\n')) != NULL){
            *point = '\0';
        }
        //printf("%s",valuein);
        // comma points to the comma before DATA
        comma = strchr(line_buf, ',');
        // make *comma NUL
        *comma = '\0';
        keyin = line_buf;
        // keyin points to KEY now

        //printf(",%s\n",keyin, valuein);
        // ignoring return for now
        (void)insertion(&root, keyin, valuein);
    }

    //bt_print(root);

    free(line_buf);

    /* Search node into tree */
    // search-keys come from either stdin or get typed in.
    // things typed in are also stdin
    while ((res = scanf("%s", buffer)) == 1) {
        trim(buffer);
        if (strcmp(buffer, "exit")== 0) {
            exit(EXIT_SUCCESS);
        }
        search(&root, buffer, counter, outputfile);
        counter = 0;
    }

    /* Deleting all nodes of tree */
    deltree(root);
    free(buffer);
    fclose(fp);
    fclose(outputfile);
    exit(EXIT_SUCCESS);
}


void trim(char* source)
{
    char* i = source;
    char* j = source;
    while (*j != 0)
    {
        *i = *j++;
        if (*i != ' ')
            i++;
    }
    *i = 0;
}

// getline() from http://stackoverflow.com/documentation/c/507/files-and-i-o-streams/8274/get-lines-from-a-file-using-getline

#include <errno.h>
#include <stdint.h>


#if !(defined _POSIX_C_SOURCE)
typedef long int ssize_t;
#endif

/* Only include our version of getline() if the POSIX version isn't available. */

#if !(defined _POSIX_C_SOURCE) || _POSIX_C_SOURCE < 200809L

#if !(defined SSIZE_MAX)
#define SSIZE_MAX (SIZE_MAX >> 1)
#endif

ssize_t getline(char **pline_buf, size_t *pn, FILE *fin)
{
  const size_t INITALLOC = 16;
  const size_t ALLOCSTEP = 16;
  size_t num_read = 0;

  /* First check that none of our input pointers are NULL. */
  if ((NULL == pline_buf) || (NULL == pn) || (NULL == fin))
  {
    errno = EINVAL;
    return -1;
  }

  /* If output buffer is NULL, then allocate a buffer. */
  if (NULL == *pline_buf)
  {
    *pline_buf = malloc(INITALLOC);
    if (NULL == *pline_buf)
    {
      /* Can't allocate memory. */
      return -1;
    }
    else
    {
      /* Note how big the buffer is at this time. */
      *pn = INITALLOC;
    }
  }

  /* Step through the file, pulling characters until either a newline or EOF. */

  {
    int c;
    while (EOF != (c = getc(fin)))
    {
      /* Note we read a character. */
      num_read++;

      /* Reallocate the buffer if we need more room */
      if (num_read >= *pn)
      {
        size_t n_realloc = *pn + ALLOCSTEP;
        char * tmp = realloc(*pline_buf, n_realloc + 1); /* +1 for the trailing NUL. */
        if (NULL != tmp)
        {
          /* Use the new buffer and note the new buffer size. */
          *pline_buf = tmp;
          *pn = n_realloc;
        }
        else
        {
          /* Exit with error and let the caller free the buffer. */
          return -1;
        }

        /* Test for overflow. */
        if (SSIZE_MAX < *pn)
        {
          errno = ERANGE;
          return -1;
        }
      }

      /* Add the character to the buffer. */
      (*pline_buf)[num_read - 1] = (char) c;

      /* Break from the loop if we hit the ending character. */
      if (c == '\n')
      {
        break;
      }
    }

    /* Note if we hit EOF. */
    if (EOF == c)
    {
      errno = 0;
      return -1;
    }
  }

  /* Terminate the string by suffixing NUL. */
  (*pline_buf)[num_read] = '\0';

  return (ssize_t) num_read;
}

#endif

void bt_print(node * leaf)
{
  if (leaf) {
    printf("%s , %s\n", leaf->name, leaf->data);
    bt_print(leaf->left);
    bt_print(leaf->right);
  }
}
int insertion(node** r, char *key, char *value)
{
    if (*r == NULL) {
        PRINT("INSERT_NEW_NODE");
        *r = malloc(sizeof(node));
        if (r == NULL) {
            return 0;
        }
        strcpy((*r)->name, key);
        strcpy((*r)->data, value);

        (*r)->left = NULL;
        (*r)->right = NULL;
    }
    // Checks for returns omitted for clarity
    else if (strcmp(key, (*r)->name) < 0) {
        PRINT("INSERT_KEY_LEFT");
        insertion(&(*r)->left, key, value);
    }
    // else this will be in the right subtree
    else if (strcmp(key, (*r)->name) > 0) {
        PRINT("INSERT_KEY_RIGHT");
        insertion(&(*r)->right, key, value);
    }
    else {
        if (strcmp(value, (*r)->data) > 0) {
            PRINT("INSERT_DATA_LEFT");
            insertion(&(*r)->left, key, value);
        }
        else if (strcmp(value, (*r)->data) < 0) {
            PRINT("INSERT_DATA_RIGHT");
            insertion(&(*r)->right, key, value);
        }
        return 0;
    }
    PRINT("INSERT_END");
    return 1;
}

void 
deltree(node * tree) {
    if (tree) {
        deltree(tree->left);
        deltree(tree->right);
        free(tree);
    }
}

node *search(node ** tree, char *key, int count, FILE * fp_out)
{
    node *tmp;
    if (!(*tree)) {
        printf("NOTFOUND %s --> %d\n", key, count);
        fprintf(fp_out, "%s --> NOTFOUND", key);
        return NULL;
    }
    else {
        if (strcmp(key, (*tree)->name) < 0) {
        PRINT("SEARCH_KEY_LEFT");
            count++;
            tmp = search(&(*tree)->left, key, count, fp_out);
            return tmp;
        }
        else if (strcmp(key, (*tree)->name) > 0) {
        PRINT("SEARCH_KEY_RIGHT");
            count++;
            tmp = search(&(*tree)->right, key, count, fp_out);
            return tmp;
        }
        else {
            printf("%s %s --> %d\n", key, (*tree)->data, count);
            return *tree;
        }
    }
}

I still cannot test it thoroughly because I have insufficient information about the input. A formal description of the DB (e.g.: in (E)BNF) would be very helpful.

Comments