C - Strange struct behavior in header file - c

I am newbie in C. I am trying to pack a function say to a struct Person. It seems fine on single c file. (Console will print "Bye.")
// all-in-one-file.c
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
void (*say)(char *sayType);
} Person;
void person_say(char *sayType);
Person initPerson();
int main()
{
Person person = initPerson();
person.say("Bye");
return 0;
}
void person_say(char *sayType)
{
if (sayType == "Hi")
{
printf("Hi.\n");
}
else if (sayType == "Bye")
{
printf("Bye.\n");
}
else
{
printf("...\n");
}
}
Person initPerson()
{
Person per;
per.say = person_say;
return per;
}
However, the console will print "..." when I try to put the struct and function to header file.
// person.h
#ifndef _PERSON_H_
#define _PERSON_H_
typedef struct
{
void (*say)(char *sayType);
} Person;
Person initPerson();
#endif
// person.c
#include <stdio.h>
#include "person.h"
void person_say(char *sayType)
{
if (sayType == "Hi")
{
printf("Hi.\n");
}
else if (sayType == "Bye")
{
printf("Bye.\n");
}
else
{
printf("...\n");
}
}
Person initPerson()
{
Person per;
per.say = person_say;
return per;
}
// main.c
#include <stdio.h>
#include <stdlib.h>
#include "person.h"
int main()
{
Person person = initPerson();
person.say("Bye");
return 0;
}
I think I have some mistakes in header file or person.c. But I cannot find the reason and the solution to fix this problem.

sayType == "Hi" this compares the addresses, not the contents. You should use strcmp (sayType, "Hi") for comparing contents of strings.
The explanation why it looks like working when they are all in one .c file is this:
When all source is in one translation unit (that is one .c file), compiler mapped string literals with identical contents to the same address. (which is implementation defined behavior that you can not depend). Therefore, identical literals have the same address so that address comparison worked.
However, when compiled in distinct translation units, compiler has no knowledge of other translation unit while compiling one, therefore they are mapped to different addresses.

Related

How to properly use 2 structs definition in one single C source file

I'd need some help with structs in C.
Basically I'm trying to create a Student and a Group struct definition.
Keep in mind that Group struct will contain Student structs previously implemented.
Below my structs definition:
Student Struct: student.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEFAULT_MATRICOLA 815010
typedef struct Student{
int matricola;
int voto_archi;
char *turno;
}Student;
int generateVoto(){
return (rand() % (30 - 18)) + 18;
}
char* generateTurno(int matricola){
char *res = malloc(2*sizeof(char) + 1);
if(matricola % 2 == 0)
res = "T2";
else
res = "T1";
return res;
}
void initializeStudent(Student s, int matricola){
s.matricola = matricola;
s.voto_archi = generateVoto();
if(s.matricola % 2 == 0){
strcpy(s.turno, "T2");
}
else{
strcpy(s.turno, "T1");
}
}
void showStudent(Student s){
printf("Matricola: %d Voto: %d Turno: %s\n", s.matricola, s.voto_archi, s.turno);
}
Student createStudent(int matricola){
int voto = generateVoto();
char *turno = generateTurno(matricola);
Student s = {matricola, voto, turno};
return s;
}
Group Struct: group.h
#include "headers.h"
#include "student.h"
#define MAX_MEMBERS 4
typedef struct Group{
int groupId;
Student *members;
int numMembers;
boolean closed;
}Group;
Group createGroup(int groupId){
Group g;
g.groupId = groupId;
g.members = malloc(MAX_MEMBERS * sizeof(Student) + 1);
g.numMembers = 0;
g.closed = FALSE;
return g;
}
void printGroup(Group g){
int index = g.numMembers;
if(index == 0)
printf(RED "Group %d is EMPTY\n" RESET, g.groupId);
else{
for(int i = 0; i < MAX_MEMBERS; i++)
showStudent(g.members[i]);
printf("\n");
}
}
Now even an empty main.c class containing only #include "student.h and #include "group.h would fail compiling but if we only add one of these two it works good.
Here's compiler's output:
Now, at last, my question:
How to create a main.c class using both student.h and group.h files?
What am I doing wrong?
You need to wrap all your header files in "include guards" so that if the header content has already been included, in any subsequent inclusion the content is skipped to prevent redefinitions:
For example for group.h you might have:
#if !defined GROUP_H
#define GROUP_H
// all Header file content here...
#endif // GROUP_H
where the macro (GROUP_H) in this case must be unique throughout teh project - it is conventional to use a name based on the file name.
An alternative supported by many toolchaisn is to use the #pragma once directive:
#pragma once
// all Header file content here...
This is less portable, but more fool-proof that a traditional include guard.
Now even an empty main.c class containing only #include "student.h and #include "group.h would fail compiling but if we only add one of these two it works good.
Apparently you lack the guard to protect your header files, which look something like this (for each .h file):
#ifndef STUDENT_H
#define STUDENT_H
// your header file goes here
#endif STUDENT_H
Alternately, you can use #pragma once at the beginning of each header file (which is supposedly a better and shorter way).

error C3861: 'ls_file': identifier not found

I am learning to write my own Virtual File system but besides the logical error in program something other than that keeps coming i checked all the declarations within the program but couldn't figure it out.
helper function
#include "header.h"
UFDT UFDTArr[50];
SUPERBLOCK SUPERBLOCKobj;
PINODE head=NULL;
void man(char *name)
{
if(name==NULL) return;
if(_stricmp(name,"ls")==0)
{
printf("Description : Used to list all information of file\n");
printf("Usage : ls\n");
}
else
{
printf("ERROR : No manual entry available\n");
}
}
void DisplayHelp()
{
printf("ls : To List Out all files \n");
printf("clear : To Clear consol\n");
}
void CreateDILB()
{
PINODE newn=NULL;
PINODE temp=head;
int i=1;
while(i<=MAXINODE)
{
newn=(PINODE)malloc(sizeof(INODE));
newn->LinkCount=newn->ReferenceCount=0;
newn->FileType=newn->FileSize=0;
newn->Buffer=NULL;
newn->next=NULL;
newn->InodeNumber=i;
if(temp==NULL)
{
head=newn;
temp=head;
}
else
{
temp->next=newn;
temp=temp->next;
}
i++;
}
}
void InitialiseSuperBlock()
{
int i=0;
while(i<50)
{
UFDTArr[i].ptrfiletable=NULL;
i++;
}
SUPERBLOCKobj.TotalInodes=MAXINODE;
SUPERBLOCKobj.FreeInode=MAXINODE;
}
void ls_file()
{
PINODE temp=head;
if(SUPERBLOCKobj.FreeInode== MAXINODE)
{
printf("Error : There are no files ");
return;
}
printf("\n File Name\tInode Number\tFile Size\tLink count\n");
printf("------------------------------------------------------------");
while(temp!=NULL)
{
if(temp->FileType!=0)
{
printf("%s\t\t%d\t\t%d\t\t%d\n");
}
temp=temp->next;
}
printf("------------------------------------------------------------");
}
main file
#include "header.h"
int main()
{
char *ptr=NULL;
int ret=0,fd=0,count=0;
char command[4][80],str[80],arr[1024];
InitialiseSuperBlock();
CreateDILB();
while(1)
{
fflush(stdin);
strcpy_s(str,"");
printf("Sachin VFS :> ");
fgets(str,80,stdin);
count=sscanf(str,"%s%s%s %s",command[0],command[1],command[2],command[3]);
if(count==1)
{
if(_stricmp(command[0],"ls")==0)
{
ls_file();
}
else if(_stricmp(command[0],"clear")==0)
{
system("cls");
continue;
}
else
{
printf("\n ERROR : Command not found!!! \n");
continue;
}
}
}
return 0;
}
header file
#define _CRT_SECURE_NO_WARNINGS
#define MAXINODE 50
#define READ 1
#define WRITE 2
#define MAXFILESIZE 1024
#define REGULAR 1
#define SPECIAL 2
#define START 0
#define CURRENT 1
#define END 2
#include<iostream>
#include <stdlib.h>
#include<string.h>
#include<io.h>
typedef struct superblock
{
int TotalInodes;
int FreeInode;
}SUPERBLOCK,*PSUPERBLOCK;
typedef struct inode
{
char FileName[50];
int InodeNumber;
int FileSize;
int FileActualSize;
int FileType;
char *Buffer;
int LinkCount;
int ReferenceCount;
int permission;
struct inode *next;
}INODE,*PINODE,**PPINODE;
typedef struct filetable
{
int readoffset;
int writeoffset;
int count;
int mode;
PINODE ptrinode;
}FILETABLE,*PFILETABLE;
typedef struct ufdt
{
PFILETABLE ptrfiletable;
}UFDT;
the one solution to this problem i got is declaring all the functions in main file above main to make compiler identify the functions but i still couldn't figure it out why it cant identify the same functions when i declare them in other file?
the default functions are working like system("cls"); but my functions are not working
could anyone help me to understand the reason of this error and possible solution ?
P.S.- I have pasted small part of my code the actual code is too long to post if anyone wants me to post it i will in comment section
In brief - you should declare ls_file() in your header.h:
void ls_file();
This is a common technique to export some objects / functions outside of file where they are defined. Both "implementation" and "client" *.c files must include that header. The former one - in order to guarantee consistency of actual definitions and publicly-visible declarations, the latter one - to provide client code with proper and explicit declarations.
... still couldn't figure it out why it cant identify the same
functions when i declare them in other file?
In general compiler should see declarations or definitions of functions / globals before any referencing to them. This is because during compilation process translator works only with one .c source, and knows nothing about another source files and their content.
P.S This answer may enlighten you a bit more.

Dynamic Memory Allocation in C not working

I'm trying to make a game that requires dynamically sized arrays in C but my code isn't working even though identical code works in another one of my programs.
Here are my #includes
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SwinGame.h" //API for graphics, physics etc
#include <math.h>
Here are my typedefs for the relevant structs used:
typedef struct position_data
{
double x;
double y;
} position_data;
typedef enum enemy_type_data {CIRCLE, TRIANGLE, SQUARE} enemy_type_data;
typedef struct enemy_data
{
position_data location;
enemy_type_data type;
bitmap bmp;
double health;
double speed;
int path_to;
} enemy_data;
typedef struct enemy_data_array
{
int size;
enemy_data *data;
} enemy_data_array;
Here is the function to add an element to the array:
void add_enemy(enemy_data_array *enemies)
{
enemy_data *new_array;
enemies->size++;
new_array = (enemy_data *)realloc(enemies->data, sizeof(enemy_data) * enemies->size);
if (new_array) //if realloc fails (ie out of memory) it will return null
{
enemies->data = new_array;
// enemies->data[enemies->size - 1] = read_enemy_data();
printf("Enemy added successfully!\n");
}
else
{
printf("FAILED. Out of Memory!\n");
enemies->size--;
}
}
And here is my function call and variable declaration in the main procedure:
int main()
{
path_data my_path[41];
enemy_data_array enemies;
enemies.size = 0;
add_enemy(&enemies);
}
Why isn't this working?
You invoked undefined behavior by passing indeterminate value enemies->data in uninitialized variable having automatic storage duration. Initialize it before using add_enemy().
int main()
{
path_data my_path[41];
enemy_data_array enemies;
enemies.size = 0;
enemies.data = 0; /* add this line */
add_enemy(&enemies);
}
0 is a null pointer constant and can safely be converted to pointer NULL. Unlike NULL, 0 will work without including any headers. Of course you can use enemies.data = NULL; with proper header included.
#2501's explanation is completely correct. Another solution is to change your implementation of add_enemy() to something like this:
void add_enemy(enemy_data_array *enemies)
{
enemy_data *new_array;
// check if size was non-zero
if (enemies->size++)
{
new_array = (enemy_data *)realloc(enemies->data, sizeof(enemy_data) * enemies->size);
}
// start new allocation
else
{
new_array = (enemy_data *)alloc(sizeof(enemy_data) * enemies->size);
}
if (new_array) //if (re)alloc fails (ie out of memory) it will return null
{
enemies->data = new_array;
// enemies->data[enemies->size - 1] = read_enemy_data();
printf("Enemy added successfully!\n");
}
else
{
printf("FAILED. Out of Memory!\n");
enemies->size--;
}
}
If fails because you haven't cleared the content of "enemies". Since it is a stack variable, it will contain whatever garbage data is on the stack.
set enemies.data to NULL in the main function and try it again.

How to omit quotation marks usage in char type?

I'm having a really hard time adjusting function to my needs. First of all look at those three files and notice how I have to call f_texture function in main function in order to make it work:
externs.h
#ifndef EXTERNS_H_
#define EXTERNS_H_
extern char t_about[100];
extern int friction;
extern int f_texture(char* ,char*);
#endif
functionA.c
#include <stdio.h>
#include "externs.h"
int main()
{
f_texture("rough","friction");
printf("Friction: %d\n", friction);
f_texture("rough","t_about");
return 0;
}
functionB.c
#include "externs.h"
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
char t_about[100];
int friction;
int f_texture(char* texture,char* what_is_needed)
{
/*Checking if both values are present*/
assert(what_is_needed);
assert(texture);
/*Static array in order to prevent it's disappearance*/
memset(t_about, '\0', sizeof(t_about));
/*Configuring variables for desired texture*/
if (strcmp(texture, "smooth") == 0)
{
strcpy(t_about, "The surface is perfectly smooth, without any "
"protuberances.\n");
friction = 0;
}
else if (strcmp(texture, "rough") == 0)
{
strcpy(t_about, "Rough bumps can be feeled under my fingertips.\n");
friction = 4;
}
/*In case of absent keyword of desired texture it will crash the program*/
else
{
assert(!what_is_needed);
}
/*Returning desired value*/
if (strcmp(what_is_needed, "t_about") == 0)
{
int i=0;
while (t_about[i] != '\0')
{
printf("%c", t_about[i]);
i++;
}
}
else if (strcmp(what_is_needed, "friction") == 0)
{
return friction;
}
/*In case of absent keyword of desired value it will crash the program*/
else
{
assert(!what_is_needed);
}
return 0;
}
And now here is my question: How to rewrite this code to make it possible to call f_texture function without using quotation marks inside? I mean instead of f_texture("abcd","efgh") just to type f_texture(abcd,efgh). I've noticed that this way it's required just after I've wrote this code.
Thanks in advance.
If you don't want to assign string constants to variables or preprocessor object macros, another option is to use preprocessor function macros, using the stringification feature:
#define call_f_texture(a,b) f_texture(#a,#b)
....
call_f_texture(rough,friction);
The C preprocessor will turn this into
f_texture("rough","friction");
You can also use some macros:
#define ROUGH "rough"
#define FRICTION "friction"
#define T_ABOUT "t_about"
int main()
{
f_texture(ROUGH, FRICTION);
printf("Friction: %d\n", friction);
f_texture(ROUGH, T_ABOUT);
return 0;
}
You can do like this,
char rough[]="rough";
char friction[]= "friction";
and call
f_texture(rough, friction);
char a[MAX] = "rouch";
char b[MAX} = "friction";
int main()
{
f_texture();
...
}
int f_texture()
{
/*Checking if both values are present*/
assert(b);
assert(a);
}
or
int f_texture(char* a,char* b)
{
/*Checking if both values are present*/
assert(b);
assert(a);
...
}
int main()
{
char a[MAX] = "rouch";
char b[MAX} = "friction";
f_texture(a,b);
...
}

Memory allocation error for structs with members that are function pointers and void pointers

I have written a straightforward C code that uses an engine to run two different algorithms depending on user input. It uses function pointers to the algorithm methods and objects. There is a nasty memory bug somewhere that I can not track down, so maybe I am allocating memory in the wrong way. What is going wrong?
Below is (the relevant parts of) a minimal working example of the code.
main.c
#include "engine.h"
int main()
{
char *id = "one";
Engine_t eng;
Engine_init(&eng);
Engine_select_algorithm(eng, id);
Engine_run(eng);
}
engine.h
typedef struct _Engine *Engine_t;
engine.c
#include "engine.h"
#include "algorithm_one.h"
#include "algorithm_two.h"
typedef struct _Engine
{
void *p_algorithm;
void (*init)(Engine_t);
void (*run)(Engine_t);
} Engine;
void Engine_init(Engine_t *eng)
{
*eng = malloc(sizeof(Engine));
(*eng)->p_algorithm = NULL;
}
void Engine_select_algorithm(Engine_t eng, char *id)
{
if ( strcmp(id, "one") == 0 )
{
eng->init = Algorithm_one_init;
eng->run = Algorithm_one_run;
}
else if ( strcmp(id, "two") == 0 )
{
eng->init = Algorithm_two_init;
eng->run = Algorithm_two_run;
}
else
{
printf("Unknown engine %s.\n", id); exit(0);
}
eng->init(eng);
}
void Engine_run(Engine_t eng)
{
eng->run(eng);
}
void Engine_set_algorithm(Engine_t eng, void *p)
{
eng->p_algorithm = p;
}
void Engine_get_algorithm(Engine_t eng, void *p)
{
p = eng->p_algorithm;
}
algorithm_one.h
typedef struct _A_one *A_one_t;
algorithm_one.c
#include "engine.h"
#include "algorithm_one.h"
typedef struct _A_one
{
float value;
} A_one;
void Algorithm_one_init(Engine_t eng)
{
A_one_t aone;
aone = malloc(sizeof(A_one));
aone->value = 13.0;
//int var = 10;
Engine_set_algorithm(eng, &aone);
}
void Algorithm_one_run(Engine_t eng)
{
A_one_t aone;
Engine_get_algorithm(eng, &aone);
printf("I am running algorithm one with value %f.\n", aone->value);
// The code for algorithm one goes here.
}
The code for algorithm_two.h and algorithm_two.c are identical to the algorithm one files.
There must be a memory bug involved, because the code runs as given, but if I uncomment the
//int var = 10;
line in algoritm_one.c the code crashes with a segmentation fault.
You pass the wrong thing to Engine_set_algorithm. You are passing the address of a local variable rather than the address of the algorithm. You need to write:
Engine_set_algorithm(eng, aone);
And also Engine_get_algorithm is wrong. You are passed a pointer by value and modify that pointer. So the caller cannot see that modification. You need it to be:
void Engine_get_algorithm(Engine_t eng, void **p)
{
*p = eng->p_algorithm;
}
I think your code would be easier if you defined a type to represent an algorithm. That type would be just a void*, but it would make the code much easier to read. What's more, I would make Engine_get_algorithm return the algorithm.
algorithm Engine_get_algorithm(Engine_t eng)
{
return eng->p_algorithm;
}
void Engine_set_algorithm(Engine_t eng, algorithm alg)
{
eng->p_algorithm = alg;
}

Resources