0

This is for a phonebook program. It reads data from a CSV but can also take input from the terminal (e.g. through scanf). It loads the csv info into a struct linked-list. We are told to use a global variable that should be the the head pointer (the type is the struct). Basically I have three files: main.c phone.c helper.c. Main.c runs the menu, asks for user input, and calls functions according to the option selected. All the functions related to those options are in the file phone.c (e.g. add, delete, list, find, etc). Any helper functions are in helper.c.

We have to use header files and a Makefile, and though I have experience with those I have run into an issue I don't know how to solve: how do I make the head variable global for multiple functions using header files? Additionally, how do I compile this properly using objects (.o files)?

I know using global variables isn't good practice necessarily but it's a requirement for this project.

Approach 1: I tried declaring the struct in helper.h and defining it in helper.c. If I #include "helper.h" into phone.c, I can access the variable from there. But then I need to #include "phone.h" into main.c to acess the functions, but that alone doesnt let me access *HEAD, so I have to #include "helper.h" into main.c as well which gives me a "multiple definitions" compilation error.

Approach 2: I declared the struct in phone.h and defined it in phone.c. But this means that I have to #include "phone.h" in helper.c AND #include "helper.h" in phone.c (to use its functions). And then I have to include both in main.c and it just becomes a big mess of multiple definition and scope errors.

We were told off-record to declare the struct in phone.h and define it in phone.c. But then how can I acess the struct data type from insde helper.h? and if I need to #include "phone.h" into helper.c, can I also #include "helper.h" into phone.c? Where does the extern declaration go?

Note: I found a way of getting it to compile. Declare struct in helper.h. #include "helper.h" in phone.h. extern struct PHONE_RECORD *HEAD in phone.h. #include "phone.c" in phone.c. However, when I run the program I get a segfault. From what I can tell, main.c has access to the *HEAD variable but phone.c doesn't.

Here's some of the code:

main.c

#include "phone.h"

int main(void) {
//calls functions from phone.c and helper.c

phone.c

#include "phone.h"

struct PHONE_RECORD *HEAD;

//a bunch of functions that call functions from helper.c

phone.h

#ifndef PHONE_H
# define PHONE_H

#include "helper.h"

#define FILENAME "./phonebook.csv"
#define BUFFER 1024

extern struct PHONE_RECORD *HEAD;

//function declarations

#endif

helper.c

#include "helper.h"

//functions called by main.c and phone.c
//I can't access *HEAD from here, it needs to be passed as a parameter

helper.h

#ifndef HELPER_H
# define HELPER_H

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

struct PHONE_RECORD {
    char name[50];
    char birthdate[12];
    char phone[15];
};

//function declarations

#endif

----SOLUTION----

In case anyone stumbles upon this in the future, I asked chat gpt and it solved the issue. Basically I had to:

  1. Declare the struct in phone.h
  2. Extern the *HEAD variable in phone.h extern struct PHONE_RECORD *HEAD;
  3. Define the *HEAD variable in phone.c struct PHONE_RECORD *HEAD = NULL;
  4. #include "phone.h" and #include "helper.h" in phone.c
  5. #include "phone.h" in helper.c
  6. Have only function declarations in helper.c
  7. #include "phone.h" and #include "helper.h" in main.c

And when compiling: Compile each file individually using gcc -c <file>

Link all the files with gcc main.o phone.o helper.o -o <program_name>

Now I can access *HEAD from all functions and no longer get a segfault.

  • 2
    You structured is correctly. *"However, when I run the program I get a segfault"* - this problem is completely unrelated and if you want to ask about *that*, you will have to write another question with a [mcve]. – Eugene Sh. Apr 10 '23 at 19:34
  • 1
    First of all, it's a *good* thing that you must pass the variable as an argument. Global variables should be avoided as much as possible. – Some programmer dude Apr 10 '23 at 19:39
  • 1
    With that said, the problem is simply that you don't declare the variable in the [*translation unit*](https://en.wikipedia.org/wiki/Translation_unit_(programming)) created from the `helper.c` source file. Is there a reason you don't have the `HEAD` declaration in the `helper.h` header file? Why is it in `phone.h`? Why is the definition in `phone.c`? Please take some time to sit down and think about the organization of your files, what needs to be declared and defined where, and what needs to be accessed from where. – Some programmer dude Apr 10 '23 at 19:43
  • @EugeneSh. Ah but the program did not segfault when I was including "phone.c" instead of the header files. This problem only showed up when I started using the .h files. Also, the debugger can't access the *HEAD variable when inside phone.c, only when in main.c. I don't know if the way I compiled it is the reason but it's definitely caused by the header file configuration or the compilation method. – Giulia Adoglio Apr 10 '23 at 20:15
  • @Someprogrammerdude That is kind of the point of my question. If I could I would organize these files completely differently, but this is the way we were told to do it: declare *HEAD in phone.c and phone.h and define *HEAD in phone.c. My question is precisely how to organize the files given those directions. – Giulia Adoglio Apr 10 '23 at 20:17
  • Your question is a bit confusing because you show `helper.c` including `mini5helper.h`, and you show `helper.h` with an include guard of `MINI5HELPER_H`. Similarly with `phone.c` including `mini5phone.h` and `phone.h` being shown as the (presumably) relevant header. Is this a result of incompletely munging your code to remove the `mini5` prefix from the names, or is there something more complex going on? If there are more headers to be shown, please show them! If the names are inconsistent, please make them consistent (one way or another — add or remove `mini5` completely). – Jonathan Leffler Apr 10 '23 at 20:55
  • @JonathanLeffler you are completely right! I removed the mini5 part to make it more understandable and forgot some instances. Thank you for pointing it out! – Giulia Adoglio Apr 11 '23 at 03:35
  • Then you either need to declare `HEAD` inside of `helper.c`, or `#include "phone.h"`. – Some programmer dude Apr 11 '23 at 13:13

0 Answers0