-1

I'm trying to create a large, multi-file program in C language but I get errors.

The program is actually a smart phone book that can perform multiple tasks like listing, adding, searching for, and deleting names.

For each of those tasks, I created a file that contains the functions and variables required to perform the task.

And here are the files I'm done with coding them:

(1) us-names.txt (a database to store the names):

Mohammed
Ali
Harry
Peter
Hussain
Mark
John
Yu
Mohammed
Christina
Mohammed
Fatima

(2) Request.c file (to receive the request from the user and perform the required task):

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

//node declaration:
typedef struct node
{
    char name[20];
    struct node* link;
}
node;

void import_names(void) ;
void add_name(string name) ;
void search_for(string name) ;
void delete_name(string name) ;


int main(int argc , string argv[])
{
    //create the hashtable and import the names:
    import_names() ;
    //check if there is any mistake in the command:
    if(argc != 3 || argc != 4)
    {
        printf("Could not recognize the command, please enter one of the three commands: \n ./phone add name \n ./phone search-for name \n ./phone delete name \n") ;
        return 1 ;
    }

    //otherwise, preform the command:
    if(strcmp(argv[1] , "add") == 0)
    {
        add_name(argv[2]) ;
        return 0 ;
    }

    if(strcmp(argv[1] , "search-for") == 0)
    {
        search_for(argv[2]) ;
        return 0 ;
    }

    if(strcmp(argv[1] , "delete") == 0)
    {
        delete_name(argv[2]) ;
        return 0 ;
    }

    else
    {
        printf("Could not recognize the command, please enter one of the three commands: \n ./phone add name \n ./phone search-for name \n ./phone delete name \n") ;
        return 1 ;
    }
}

3- Import.c file (to import the names from the text file and hash them and store them in a hashtable) :

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

//node declaration:
typedef struct node
{
    char name[20];
    struct node* link;
}
node;

unsigned int hash(char* buffer , unsigned int CAPACITY) ;

void import_names(void)
{
    //declarations:
    FILE* fp = fopen("us-names.txt" , "a+") ;
    if(fp == NULL)
    {
        printf("CANNOT OPEN THE FILE !\n") ;
        fclose(fp) ;
        exit ;
    }

    char buffer[20] ;
    unsigned int key = 0;
    unsigned int CAPACITY = 100 ;
    struct node* temp = NULL ;
    struct node* hashtable[CAPACITY] ;
    for(int i = 0 ; i < CAPACITY ;i++)
    {
        hashtable[i] = NULL ;
    }
    struct node* curr = NULL ;
    int num_of_names = 0;

    //use a loop to iterate over the FILE:
    for(int i = 0 ; !feof(fp) ; i++)
    {
        //Import name from the FILE & store into buffer:
        fgets(buffer , 20 , fp) ;
        //pass the name into the hash_function and get the key:
        key = hash(buffer , CAPACITY) ;

        //put the name in a node then in it's right place in the hashtable using the key:
        temp = malloc(sizeof(struct node)) ;
        sprintf(temp->name , "%s" , buffer) ;
        temp->link = NULL ;

        //if the key place of the hashtable is already populated, preform the collision protocol!:
        if(hashtable[key] != NULL)
        {
            for(curr = hashtable[key] ; curr->link != NULL ; curr = curr->link)
            {

            }
            curr->link = temp ;
        }
        //else if it's unpopulated, just store the name in this place:
        else
        {
            hashtable[key] = temp ;
        }
        num_of_names++ ;
    }

    //close the FILE :
    fclose(fp) ;
}

4- Hash.c file ( a small file contains a hash function ) :

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

unsigned int hash(char* buffer , unsigned int CAPACITY)
{
    unsigned int sum = 0 ;
    for(int i = 0; buffer[i] != '\0' ;i++)
    {
        sum += buffer[i] ;
    }
    return sum % CAPACITY ;
}

5- Search.c file ( contains a sort of binary search function to search for any name) :

#include <stdio.h>
#include <stdlib.h>
#include <cs50.h>
#include <stdint.h>
#include <string.h>
#include "phonehead.h"
//node declaration:
typedef struct node
{
    char name[20];
    struct node* link;
}
node;

unsigned int CAPACITY = 100 ;
struct node* hashtable[CAPACITY] ;

unsigned int hash(char* buffer , unsigned int CAPACITY) ;

void search_for(string name)
{
    //hash the name to get the place in which the wanted name is stored in the hash function:
    unsigned int place = hash(name,CAPACITY);

    //go to the location in the hashtable in which the name is stored, and check if the name is in the first node of the chain.
    if(strcmp(hashtable[place]->name , name) == 0)
    {
        printf("FOUND\n") ;
    }
    //else, go to the node pointed by the current node and check if it contain the wanted name, and repeat this step until reaching null.
    else if(strcmp(hashtable[place]->name , name) != 0)
    {
       struct node* curr = NULL ;
       for(curr = hashtable[place]->link ; curr != NULL ; curr = curr->link)
       {
           if(strcmp(curr->name , name) == 0)
           {
               printf("FOUND\n");
               exit ;
           }
       }
       printf("NOT FOUND!\n") ;
    }

}

In addition to a header file :

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

typedef struct node
{
    char name[20];
    struct node* link;
}
node;
unsigned int hash(char* buffer , unsigned int CAPACITY) ;
unsigned int CAPACITY = 100 ;
struct node* hashtable[CAPACITY] ;
void import_names(void) ;
void add_name(string name) ;
void search_for(string name) ;
void delete_name(string name) ;

however when try to link/compile the files using the command

gcc phonehead.h requist.c Import.c Hash.c Search.c -o phone

I receive these errors:

phonehead.h:15:14: error: variably modified ‘hashtable’ at file scope
   15 | struct node* hashtable[CAPACITY] ;
      |              ^~~~~~~~~
In file included from Search.c:6:
phonehead.h:15:14: error: variably modified ‘hashtable’ at file scope
   15 | struct node* hashtable[CAPACITY] ;
      |              ^~~~~~~~~
Search.c:8:16: error: redefinition of ‘struct node’
    8 | typedef struct node
      |                ^~~
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Moe Hasan
  • 11
  • 2
  • 1
    Add a header guard at the top of `phonehead.h` (like `#pragma once` if your compiler supports it) and remove the duplicate definition of `node` from `Search.c` – Ted Lyngmo Oct 05 '21 at 19:10
  • 1
    Also: `gcc phonehead.h requist.c Import.c Hash.c Search.c -o phone` should _not_ include the header file `phonehead.h`. Make it `gcc requist.c Import.c Hash.c Search.c -o phone` – Ted Lyngmo Oct 05 '21 at 19:15
  • 1
    Ted lyngmo will do, thanks for the advice. – Moe Hasan Oct 06 '21 at 13:19

1 Answers1

3

This declaration

struct node* hashtable[CAPACITY] ;

declares a variable length array at file scope. You may not declare a variable length array at file scope. Objects declared in a file scope have static storage duration but variable length arrays may have only automatic storage duration that is they are allowed to be defined at a block scope.

Instead of declaring the variable CAPACITY that is used as the size of an array that leads to declaring a variable length array

unsigned int CAPACITY = 100 ;
struct node* hashtable[CAPACITY] ;

you could use either a define instruction like

#define CAPACITY 100
struct node* hashtable[CAPACITY] ;

or a numeration constant like

enum { CAPACITY = 100 };
struct node* hashtable[CAPACITY] ;

Moreover you declared such an array in the file scope twice: in the header file phonehead.h and in the file Search.c that includes the header. There is no sense to declare the array twice. You should declare it only one time. As the array at file scope is not initialized explicitly such a declaration introduces a tentative definition.

And you two times defined the struct node

typedef struct node
{
    char name[20];
    struct node* link;
}
node;

in the header phonehead.h and in the module that includes the header

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335