We have to create a binary tree with car models and modify it in different ways. The main problem for me is the use of a double pointer (struct tree_st **root
).
Why can't I just use a standard, single pointer?
Here's the code if you need more details of what I'm talking about:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_SIZE 20+1
typedef struct auto_st //auto as in "car"
{
char marka[MAX_SIZE]; //marka as in "car model"
int kubikaza; // "cubage"
int godiste; // "year of production"
struct auto_st *left, *right;
}AUTO;
FILE *safe_fopen(char *filename, char *mode, int exit_code);
void init(AUTO **root);
AUTO *create_new(char marka[], int kubikaza, int godiste);
void add_location(AUTO *new, AUTO **root);
void read_file(FILE *in, AUTO **root);
void write_one(FILE *out, AUTO *root);
void write_all(FILE *out, AUTO *root);
void find(AUTO *root, char marka[]);
AUTO *newest(AUTO *root, int max_kub);
int main(int arg_num, char *args[])
{
AUTO *root;
if(arg_num!=4)
{
printf("WRONG NUMBER OF ARGUMENTS!\n");
exit(1);
}
int max_kub = atoi(args[1]);
char *in_filename = args[2];
char *out_filename = args[3];
FILE *in = safe_fopen(in_filename,"r",10);
FILE *out = safe_fopen(out_filename,"w",11);
init(&root);
read_file(in,&root);
write_all(out,root);
AUTO *best = newest(root, max_kub);
if(best==NULL)
{
printf("CAR DOESN'T EXIST!\n");
}
else
{
write_one(out,best);
}
find(root,"Ferrari");
fclose(in);
fclose(out);
return EXIT_SUCCESS;
}
FILE *safe_fopen(char *filename, char *mode, int exit_code)
{
FILE *pf = fopen(filename,mode);
if(pf==NULL)
{
printf("CAN'T OPEN FILE %s\n", filename);
exit(exit_code);
}
return pf;
}
void init(AUTO **root)
{
*root = NULL;
}
AUTO *create_new(char marka[], int kubikaza, int godiste)
{
AUTO *new = (AUTO*)malloc(sizeof(AUTO));
if(new == NULL)
{
printf("NOT ENOUGH RAM!!\n");
exit(5);
}
strcpy(new->marka,marka);
new->kubikaza = kubikaza;
new->godiste = godiste;
new->left = NULL;
new->right = NULL;
return new;
}
void add_location(AUTO *new, AUTO **root)
{
if(*root==NULL)
{
*root = new;
}
else if(strcmp((*root)->marka,new->marka)==1)
{
add_location(new,&((*root)->left));
}
else if(strcmp((*root)->marka,new->marka)==-1)
{
add_location(new,&((*root)->right));
}
}
void read_file(FILE *in, AUTO **root)
{
char tmarka[MAX_SIZE];
int tkubikaza;
int tgodiste;
while(fscanf(in,"%s %d %d",tmarka, &tkubikaza, &tgodiste)!=EOF)
{
AUTO *new = create_new(tmarka, tkubikaza, tgodiste);
add_location(new,root);
}
}
void write_one(FILE *out, AUTO *root)
{
fprintf(out,"%s %d %d\n",root->marka, root->kubikaza, root->godiste);
}
void write_all(FILE *out, AUTO *root)
{
if(root!=NULL)
{
write_all(out,root->left);
write_one(out,root);
write_all(out,root->right);
}
}
void find(AUTO *root, char tmarka[])
{
if(root!=NULL)
{
if(strcmp(root->marka,tmarka)==0)
{
printf("%s %d %d\n",root->marka, root->kubikaza, root->godiste);
}
else if(strcmp(root->marka,tmarka)==1)
{
find(root->left, tmarka);
}
else if(strcmp(root->marka,tmarka)==-1)
{
find(root->right, tmarka);
}
}
}
AUTO *newest(AUTO *root, int max_kub)
{
if(root==NULL)
{
return NULL;
}
AUTO *best = NULL;
if(root->kubikaza <= max_kub)
{
best = root;
}
AUTO *left = newest(root->left, max_kub);
if(left!=NULL)
{
if(best==NULL || left->godiste > best->godiste)
{
best = left;
}
}
AUTO *right = newest(root->right, max_kub);
if(right!=NULL)
{
if(best==NULL || right->godiste > best->godiste)
{
best = right;
}
}
return best;
}
A pointer is a pointer, and nothing more. It points to something else.
Take for example
The variable
ptr_to_int
points to the location whereint_value
exists.Now to have a "double pointer":
The variable
ptr_to_ptr_to_int
points to whereptr_to_int
exists.More "graphically" the above could be seen as something like
There are basically three uses of "double pointers", both related to arrays.
In the case you show, with the functions
init
andread_file
taking a "double pointer", it is the last case, to emulate pass by reference.