how do i use vars, functions and structs in other files? - c

In timer.c I have
typedef struct Timer {
int startTicks;
int pausedTicks;
int paused;
int started;
} Timer;
void Init( Timer *t )
{
t->startTicks = 0;
t->pausedTicks = 0;
t->paused = 0;
t->started = 0;
}
What do i need to do in main.c to make use of this struct and functions in that file?

In general, .c files contain definitions and .h files contain declarations. A better approach would be to keep your definitions in a header:
//timer.h
#ifndef TIMER_H //include guard
#define TIMER_H
typedef struct Timer { //struct declaration
int startTicks;
int pausedTicks;
int paused;
int started;
} Timer;
void Init( Timer *t ); //method declaration
#endif
//timer.c
#include "timer.h"
void Init( Timer *t ) //method definition
{
t->startTicks = 0;
t->pausedTicks = 0;
t->paused = 0;
t->started = 0;
}
//main.c
#include "timer.h" //include declarations
int main()
{
Timer* t = malloc(sizeof(Timer));
Init(t);
free(t);
return 0;
}

Learn to use header files (usually named *.h) and #include them.
Learn how to compile a program with several compilation units, e.g. with a Makefile.
Don't forget to enable all warnings and debugging information (with GCC, that means gcc -g -Wall, i.e. CFLAGS=-g -Wall in your Makefile).

Related

C "dereferencing pointer to incomplete type struct" in thread

I have two separate programs, one is being called as a thread, while the other contains a struct and main. Below is snippets of the code, and further explanation:
In my main program (we will call this main.c):
# include "thread.c" // my thread program
# include <pthread.h>
struct myVariables {
double dt;
};
void simulate(int neuronCount, double dt) {
// declare and assign struct values
struct myVariables *vars;
vars = (struct myVariables*)malloc(sizeof(struct myVariables));
vars->dt = dt;
for(int i=0 ; i<neuronCount ; i++) {
pthread_t neuron;
pthread_create(&neuron, NULL, thread, (void*) vars);
}
}
int main(int argc, char *argv[]) {
int neuronCount = 5;
double dt = 0.01;
simulate(neuronCount, dt);
}
In my thread program, which is a separate file (we will call this thread.c):
# include <stdio.h>
# include <stdlib.h>
# include <pthread.h>
// Function for thread to execute.
void* thread(void* variables) {
struct myVariables *vars = (struct myVariables *) variables;
double x = vars->dt; // ISSUE IS IN THIS LINE
printf("x = %f\n", x);
// extra calculations that i cut out
}
I have looked at many other answers and solutions for this error and I have tried following all of them. One of which was changing (void*) vars in the pthread_create() line to &vars, but the error did not change. I have made sure to copy everything exactly, but I am stumped. Any and all help would be greatly appreciated :)
You have to make the structure myVariables visible from the thread function.
You can do that by separating its declaration to another header file and use that, for example.
Also note that passing .c file to #include is generally considered as a bad idea because it may lead to multiple-definition error. Instead of that, you should compile .c files separately and link the compiled object files.
main.c
# include <pthread.h>
# include "struct.h"
void simulate(int neuronCount, double dt) {
// declare and assign struct values
struct myVariables *vars;
vars = (struct myVariables*)malloc(sizeof(struct myVariables));
vars->dt = dt;
for(int i=0 ; i<neuronCount ; i++) {
pthread_t neuron;
pthread_create(&neuron, NULL, thread, (void*) vars);
}
}
int main(int argc, char *argv[]) {
int neuronCount = 5;
double dt = 0.01;
simulate(neuronCount, dt);
}
struct.h
#ifndef STRUCT_H_GUARD_8D7AA9A3_CC2D_4B76_B24D_8925426D9552
#define STRUCT_H_GUARD_8D7AA9A3_CC2D_4B76_B24D_8925426D9552
struct myVariables {
double dt;
};
#endif
thread.c
# include <stdio.h>
# include <stdlib.h>
# include <pthread.h>
# include "struct.h"
// Function for thread to execute.
void* thread(void* variables) {
struct myVariables *vars = (struct myVariables *) variables;
double x = vars->dt; // ISSUE IS IN THIS LINE
printf("x = %f\n", x);
// extra calculations that i cut out
}

Compile time error when using struct in other c file

I am using a structure that I defined in main.h and now using it in stack.c. In my main.h I have defined struct details and struct library. When I access them in stack.c I get the following error. When I am running a single main.c file then it's having no issues, so, I assume the issue lies in the stack.c or stack.h file.
Undefined symbols for architecture x86_64:
"_details", referenced from:
_main in main.o
_library_details in main.o
_push in stack.o
(maybe you meant: _library_details)
"_library", referenced from:
_main in main.o
_library_details in main.o
_push in stack.o
(maybe you meant: _library_details)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation
Here are my code snippets:
main.c
// write code below
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "main.h"
void library_details(void);
FILE *fp;
int choice, indexer = 1;
//details_struct details[maxsize];
//library_struct library[maxsize];
int main(void)
{
// library = malloc(sizeof(library_struct) * 2);
fp = fopen("input.txt","r");
library_details();
for (int i = 1; i < indexer; i++)
{
if(library[i].type == is_book)
{
printf("Item %i is book: %s with %i pages\n", i, details[i].title, details[i].pages);
}
else if(library[i].type == is_article)
{
printf("Item %i is article: %s with %i pages\n", i, details[i].title, details[i].pages);
}
}
fclose(fp);
//free(library);
return 0;
}
main.h
#ifndef __MAIN_H_
#define __MAIN_H_
enum book_type {is_book, is_article};
typedef struct library_struct
{
enum book_type type;
void *item;
}library_struct;
typedef struct details_struct
{
char title[50];
int pages;
}details_struct;
// external variables
extern int choice, indexer;
extern details_struct details[100];
extern library_struct library[100];
// library details
void library_details(void);
#endif // __MAIN_H_
stack.c
// stack.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "stack.h"
#include "main.h"
//functions declarations
void push(void);
stack books_stack[100];
int top = 0;
int stack_main(void)
{
return 0;
}
void push()
{
if(top >= 99)
{
printf("Stack Overflow\n");
exit(-1);
}
else
{
if(library[top].type == is_book)
{
strcpy(books_stack[top].s_title, details[top].title);
books_stack[top].s_pages = details[top].pages;
}
}
}
stack.h
#ifndef __STACK_H_
#define __STACK_H_
typedef struct stack
{
char s_title[50];
int s_pages;
}stack;
// functions declaration
void push();
#endif // __STACK_H_
Is there any issue with struct declarations?
Haven't used C in a while so I can't straight answer your question, but I made your code compile. However the compiled program has a C runtime abort. (Potentially some exception or something...) Examine this and consider the diff... in h you never instantiate, you declare, in c you instantiate your declaration. I don't know why you were doing extern + trying to instantiate... The other answers noted a most of the areas I messed with.
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "main.h"
FILE *fp;
int choice, indexer = 1;
int maxsize = 50;
details_struct details[100];
library_struct library[100];
void library_details(void)
{
return;
}
int main(void)
{
// library = malloc(sizeof(library_struct) * 2);
fp = fopen("input.txt","r");
library_details();
for (int i = 1; i < indexer; i++)
{
if(library[i].type == is_book)
{
printf("Item %i is book: %s with %i pages\n", i, details[i].title, details[i].pages);
}
else if(library[i].type == is_article)
{
printf("Item %i is article: %s with %i pages\n", i, details[i].title, details[i].pages);
}
}
fclose(fp);
//free(library);
return 0;
}
main.h
#ifndef __MAIN_H_
#define __MAIN_H_
enum book_type {is_book, is_article};
typedef struct library_struct
{
enum book_type type;
void *item;
} library_struct;
typedef struct details_struct
{
char title[50];
int pages;
} details_struct;
// external variables
extern int choice, indexer;
details_struct details[];
library_struct library[];
// library details
void library_details(void);
#endif // __MAIN_H_
stack.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "stack.h"
//functions declarations
void push(void);
stack books_stack[100];
int top = 0;
int stack_main(void)
{
return 0;
}
void push() {
if (top >= 99) {
printf("Stack Overflow\n");
exit(-1);
} else {
if (library[top].type == is_book) {
strcpy(books_stack[top].s_title, details[top].title);
books_stack[top].s_pages = details[top].pages;
}
}
stack.h
#ifndef __STACK_H_
#define __STACK_H_
#include "main.h"
typedef struct stack
{
char s_title[50];
int s_pages;
} stack;
// functions declaration
void push();
#endif // __STACK_H_
}
library an library_details are not exist in your code
You declare the function in main.h, but is not in in main.c
And, with library[], you are using but is not declared
You seem to have commented out the variable declarations:
//details_struct details[maxsize];
//library_struct library[maxsize];
So, neither details nor library are defined, and this is what the compiler is complaining about.

Makefile in C (ubuntu) multiple definition

I am learning c and trying to build using makefile. I am stuck on the following error and don't know what to do next.
the build command is
gcc -o logfind logfind.o cmdargutils.o filesystem_utils.o file_utils.o strutils.o
If I need both file_utils.o and cmdargutils.o but if I add both I get the following error.
error screenshot
ERROR
file_utils.o:(.rodata+0x0): multiple definition of `MAX_LINE'
logfind.o:(.rodata+0x0): first defined here
collect2: error: ld returned 1 exit status
Makefile:2: recipe for target 'logfind' failed
make: *** [logfind] Error 1
The source is:
Makefile
logfind: clean logfind.o
gcc -o logfind logfind.o cmdargutils.o filesystem_utils.o file_utils.o strutils.o
logfind.o: logfind.c cmdargutils.o file_utils.o filesystem_utils.o strutils.o error_codes.h
gcc -c logfind.c
cmdargutils.o: cmdargutils.c cmdargutils.h
gcc -c cmdargutils.c
file_utils.o: file_utils.c file_utils.h
gcc -c file_utils.c
filesystem_utils.o: filesystem_utils.c filesystem_utils.h
gcc -c filesystem_utils.c
strutils.o: strutils.c strutils.h
gcc -c strutils.c
clean:
rm -f *.o logfind
cmdargutils.h
#ifndef CMD_ARG_UTILS
#define CMD_ARG_UTILS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
#include "error_codes.h"
#include "strutils.h"
struct Argument {
bool is_and_operation;
int count;
char **search_terms;
};
struct Argument *argument_create(int argc, char **argv, int start, bool is_and_operation);
void argument_destroy(struct Argument *argument);
struct Argument *parse_arguments(int argc, char **argv);
#endif
error_codes.h
#ifndef ERROR_CODES
#define ERROR_CODES
enum error_codes {
MEMORY_ERROR,
INPUT_ERROR
};
#endif
file_utils.h
#ifndef FILE_UTILS
#define FILE_UTILS
#define _GNU_SOURCE
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include "cmdargutils.h"
const size_t MAX_LINE = 1024;
bool is_match(char *, struct Argument *);
bool scan_file(char *, struct Argument *);
#endif
filesystem_utils.h
#ifndef FILESYSTEM_UTILS
#define FILESYSTEM_UTILS
#include <glob.h>
#include <string.h>
#include "strutils.h"
struct SearchFiles {
int count;
char **paths;
};
struct SearchFiles *search_files_create(int count, char** paths);
void search_files_destroy(struct SearchFiles *search_files);
struct SearchFiles *scan_directory(char *directory_path, char *pattern);
#endif
strutils.h
#ifndef STRUTILS
#define STRUTILS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "error_codes.h"
char *strdup(const char *source);
char **copy_string_array(char **source, int start, int end);
#endif
logfind.c
#include <stdio.h>
#include <stdlib.h>
#include <glob.h>
#include "cmdargutils.h"
#include "filesystem_utils.h"
#include "file_utils.h"
int main(int argc, char **argv) {
struct Argument *argument = parse_arguments(argc, argv);
int i = 0;
struct SearchFiles *search_files = scan_directory(".", "*.*");
for(i = 0; i < search_files->count; i++) {
scan_file(search_files->paths[i], argument);
}
search_files_destroy(search_files);
argument_destroy(argument);
return 0;
}
cmdargutils.c
#include "cmdargutils.h"
struct Argument *argument_create(int argc, char **argv, int start, bool is_and_operation){
struct Argument *argument = (struct Argument *)malloc(sizeof(struct Argument));
if(!argument) {
printf("Could not initialize arguments.\n");
exit(MEMORY_ERROR);
}
argument->count = argc - start;
argument->is_and_operation = is_and_operation;
argument->search_terms = copy_string_array(argv, start, argc);
return argument;
}
void argument_destroy(struct Argument *argument){
int i = 0;
for(i = 0; i < argument->count; i++) {
free(argument->search_terms[i]);
}
free(argument->search_terms);
free(argument);
argument = NULL;
}
struct Argument *parse_arguments(int argc, char **argv) {
struct Argument *argument = NULL;
bool is_and_operation = true;
int start = 0;
if(argc < 2) {
printf("Not enough arguments\n");
exit(INPUT_ERROR);
}
char *operation = argv[1];
if(strcmp(operation, "-o") == 0) {
is_and_operation = false;
if(argc < 3) {
printf("Not enough arguments\n");
exit(INPUT_ERROR);
}
}
start = is_and_operation ? 1 : 2;
argument = argument_create(argc, argv, start, is_and_operation);
return argument;
}
file_utils.c
#include "file_utils.h"
bool is_match(char *line, struct Argument *argument) {
int i = 0;
bool isMatch = false;
for(i = 0; i < argument->count; i++) {
char *found = strcasestr(line, argument->search_terms[i]);
if(!found) {
if(argument->is_and_operation) {
isMatch = false;
break;
} else {
continue;
}
} else {
isMatch = true;
if(argument->is_and_operation) {
continue;
} else {
break;
}
}
}
return isMatch;
}
bool scan_file(char *path, struct Argument *argument) {
FILE *file = fopen(path, "r");
int line_number = 0;
char *line = malloc(MAX_LINE);
while(fgets(line, MAX_LINE - 1, file)!= NULL) {
++line_number;
if(is_match(line, argument)) {
printf("%s:%d\n", path, line_number);
printf("\t%s\n", line);
}
}
free(line);
fclose(file);
}
filesystem_utils.c
#include "filesystem_utils.h"
struct SearchFiles *search_files_create(int count, char** paths) {
struct SearchFiles *search_files = (struct SearchFiles *)malloc(sizeof(struct SearchFiles));
search_files->count = count;
search_files->paths = copy_string_array(paths, 0, count);
return search_files;
}
void search_files_destroy(struct SearchFiles *search_files) {
int i = 0;
for(i = 0; i < search_files->count; i++) {
free(search_files->paths[i]);
}
free(search_files->paths);
free(search_files);
search_files = NULL;
}
struct SearchFiles *scan_directory(char *directory_path, char *pattern) {
glob_t globbuf;
int error = glob(pattern, GLOB_MARK, NULL, &globbuf);
if(!error) {
struct SearchFiles *search_files = search_files_create(globbuf.gl_pathc, globbuf.gl_pathv);
globfree(&globbuf);
return search_files;
}
return NULL;
}
strutils.c
#include "strutils.h"
char *strdup(const char *source) {
char *dest = malloc(strlen(source) + 1);
if(!dest) {
printf("Memory allocation error\n");
exit(MEMORY_ERROR);
}
strcpy(dest, source);
return dest;
}
char **copy_string_array(char **source, int start, int end) {
char **dest = (char **)malloc(sizeof(char *) * (end - start));
int di = 0;
int si = start;
for(di = 0, si = start; si < end;
si++, di++) {
dest[di] = strdup(source[si]);
}
return dest;
}
read documentation!
First, take a few hours to read documentation of GNU make, and read how to invoke GCC. You also need to understand more about the preprocessor, so read documentation of cpp. You want to take advantage of builtin GNU make rules (so run make -p to understand them) and variables. See also this answer. You could use remake (as remake -x) to debug your Makefile. You apparently don't understand how make and how gcc should be used, so you need to read more. Read also a C tutorial, look into some C reference, and glance when needed into the C11 standard n1570. Of course, read the documentation of every function you use (e.g. printf(3) etc..). For Linux system programming, read a book like ALP and relevant man pages from syscalls(2) and intro(3) etc...
Then read How to debug small programs. You certainly want to compile with all warnings and debug info.
a better Makefile
You might try something like:
# a better Makefile
# your C compiler
CC= gcc
# the verbose remove
RM= rm -vf
# your C compilation flags
CFLAGS= -Wall -Wextra -g
# your C source files
MY_CSOURCES= logfind.c cmdargutils.c filesystem_utils.c file_utils.c strutils.c
# the corresponding object files
MY_OBJECTS= $(patsubst %.c, %.o, $(MY_CSOURCES))
# the conventional phony targets
.PHONY: all clean
# the only program is for the default target all
all: logfind
logfind: $(MY_OBJECTS)
$(LINK.c) $< -o $#
# cleaning the mess
clean:
$(RM) logfind *.o *~
Of course, you need dependencies for object files on header files. You could compute them automatically, but it is simpler to explicit them, so add something like:
strutils.o: strutils.c strutils.h
and so on for each other object files.
BTW my HelloWorld/ directory on github is a tutorial example for using make
your multiple definition bug
You are getting multiple definition of MAX_LINE because it is defined in a header file included by several translation units, hence several translation units define it.
So either make it a preprocessor constant #define MAX_LINE 1024 in your header file_utils.h, or put there only a declaration like extern const int MAX_LINE; and define it only once in a single translation unit, as const int MAX_LINE=1024; in file_utils.c
general hints
I strongly recommend doing some iterative and incremental development: code only one or two dozen lines at once, then compile them, improve them to get no warnings, debug them with the GDB debugger and test them. At last repeat all this till satisfied. I do recommend using also a version control system (like git) even for school homework.
You might want to use valgrind to hunt memory leaks and other dynamic memory allocation bugs.
You could also use some static source analyzer like clang-analyzer or even Frama-C.
Once your program is debugged, you might add optimization flags like -O2 into your CFLAGS (in particular if you benchmark it with time(1)).
You could be interested by ntfw(3).

Forward declaration C

I have 2 header files api.h and impl.h
api.h is visible to outside files and will be included in other ".c" files. So api.h includes impl.h
api.h defines 2 structures
typedef struct
{
uint32_t att;
union
{
struct
{
void* buffer;
size_t length;
} x;
struct
{
int a, b;
} v;
} content;
}dummy;
and impl.h has some other structures and function def which uses this structure.
I tried forward declaration but it doesn't help me .
Please help .
Actually, your dummy is not a structure, but a typedef to an unnamed structure. Try naming the structure, you can then forward-declare it:
typedef struct sdummy dummy; // forward declaration
void foo(dummy *);
struct sdummy { ... }; // definition
Either reorder your code in api.h so the type declaration precedes the #include "impl.h" or give your (currently anonymous) structure itself a name like dummy, dummy_, dummy_s so you can add a forward declaration
typedef struct dummy_ dummy;
to impl.h.
If you want to hide the details of your struct then you have to define it in some .c file, let's say impl.c, so that it has internal linkage to that compilation unit. To use it you have to expose create, destroy, getter and setter functions. So a basic setup would look like this:
api.h with forward declaration for your struct
// forward declaration
typedef struct dummy* dummy_t;
// create / destroy / setter / getter (omitted)
dummy_t alloc_dummy();
void free_dummy(dummy_t);
void set_number(dummy_t, int);
void set_string(dummy_t, char*);
void print_dummy(dummy_t);
Then comes impl.c
#include "api.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
struct dummy {
int n;
char* s;
};
dummy_t alloc_dummy()
{
return malloc(sizeof(struct dummy));
}
void free_dummy(dummy_t dummy)
{
if(dummy) {
free(dummy->s);
free(dummy);
}
}
void set_number(dummy_t dummy, int n)
{
if(dummy) {
dummy->n = n;
}
}
void set_string(dummy_t dummy, char* s)
{
if(dummy && s) {
dummy->s = strdup(s);
}
}
void print_dummy(dummy_t dummy)
{
if(dummy) {
printf("%d, %s\n", dummy->n, dummy->s);
}
}
And finally the usage in some other C files, here main.c
#include "api.h"
int main(int argc, char** argv)
{
// struct dummy d; // error! type is unknown
// instead use the create function
dummy_t d = alloc_dummy();
// d->n = 1; // error! dereference of unknown type
// instead use the setter function
set_number(d, 1);
set_string(d, "Hello, world!");
print_dummy(d);
free_dummy(d);
return 0;
}
Ouput
1, Hello, world!

C pointers - allocate a global pointer in one file using it in another file?

I need several global pointers to be shared among a few files - the pointers are essentially arrays of double whose lengths are only determined at runtime.
I include here the pieces of the code that caused the issue. This is not the exact code, but it illustrates all the points precisely:
foo.h
#ifndef FOOH
#define FOOH
/* ------------------
COMMON VARIABLES
---------------------*/
// create_bundles.c
extern double *all_bundle;
/* ------------------
COMMON FUNCTIONS
---------------------*/
// create_bundles.c
void create_bundles(int num_firm);
// memory_allocation.c
void allocate_memory(int num_firm, int num_bundle);
void clean_memory(void);
#endif
create_bundles.c
#include "foo.h"
extern double *all_bundle;
void create_bundles(int num_firm) {
int i;
for (i = 0; i < num_firm; i++) {
all_bundle[i] = 1
}
memory_allocation.c
#include "foo.h"
// create_bundles.c
double *all_bundle = NULL;
void allocate_memory(int num_firm, int num_bundle) {
all_bundle = calloc(num_bundle * num_firm, sizeof(double));
}
void clean_memory(void) {
free(all_bundle);
}
main.c
#include "foo.h"
void main(int num_firm, int num_bundle) {
allocate_memory(num_firm, num_bundle);
create_bundles(num_firm);
clean_memory();
}
What happened is that if I print out all_bundle[i] it'll all be 0, and then it'll give me a segmentation error.
Why the error and how to fix it?
The problem is not in global pointer, but something else. Keep looking for the problem in your common code. I hope you are trying to print contents of all_bundle array before calling clean_memory. I have edited your code a little bit and it works great without any segmentation errors and prints 1.0000. Here it is, take a look:
foo.h:
#ifndef FOOH
#define FOOH
// create_bundles.c
extern double *all_bundle;
// create_bundles.c
void create_bundles(int num_firm);
// memory_allocation.c
void allocate_memory(int num_firm, int num_bundle);
void clean_memory(void);
#endif
memory_allocation.c:
#include <stdlib.h>
#include "foo.h"
double *all_bundle = 0;
void allocate_memory(int num_firm, int num_bundle) {
all_bundle = calloc(num_bundle * num_firm, sizeof(double));
}
void clean_memory(void) {
free(all_bundle);
}
create_bundles.c:
#include "foo.h"
void create_bundles(int num_firm) {
int i;
for (i = 0; i < num_firm; i++) {
all_bundle[i] = 1;
}
}
main.c:
#include <stdio.h>
#include "foo.h"
int main(int argc, char *argv[]) {
allocate_memory(100, 1);
create_bundles(100);
{
int i;
for(i = 0; i < 100; ++i)
printf("%f\n", all_bundle[i]);
}
clean_memory();
return 0;
}
Have a header file to access the memory (i.e. add stuff to it, remove stuff from it, readf bits of it, etc).
Have the corresponding .c (or .cpp if that fancies you) to do the magic. And then use static to define the memory.
This is a simple and easy solution to your problem and also enables you to change the implementation if it is required to do so.

Resources