I would like learn how to pass, by reference, an array of structs to the second function called/executed from within the first function. My goal is to modify/change the contents of arbitrary struct from the second function only. The code below works, but, unfortunately, does not do exactly what I want to achieve. I would to have access to arbitrary struct within second function. In other words, I would like to process all structs (using for loop) within second function by calling/executing first function in main only once and not using for loop.
The second function, in the code below, is named passByReference_inner.
array_of_struct.h :
struct card
{
int face;
int nose;
};
typedef struct card HEAD ;
/* prototype */
extern void passByReference(HEAD **c); /* first function */
extern void passByReference_inner(HEAD *c); /* second function */
first function: (passByReference)
#include <stdio.h>
#include "array_of_struct.h"
void passByReference(HEAD **c)
{
passByReference_inner (*c); /* second function */
}
second function: (passByReference_inner)
#include <stdio.h>
#include "array_of_struct.h"
void passByReference_inner(HEAD *c)
{
c->face = (c->face) + 1000;
c->nose = (c->nose) + 2000;
}
main:
#include <stdio.h>
#include "array_of_struct.h"
int main(void)
{
int i;
static HEAD c[12];
static HEAD *cptr[12];
for ( i = 0; i < 12; i++ )
{
c[i].face = i + 30;
c[i].nose = i + 60;
cptr[i] = &c[i];
}
for ( i = 0; i < 12; i++ )
{
passByReference(&cptr[i]); /* first function */
}
return 0;
}
I think what you are trying to do is this
#include <stdio.h>
struct card
{
int face;
int nose;
};
typedef struct card HEAD ;
/* prototype */
void passByReference(HEAD *c, int count); /* first function */
void passByReference_inner(HEAD *c); /* second function */
void passByReference(HEAD *c, int count)
{
int i;
for (i = 0 ; i < count ; i++)
passByReference_inner (&(c[i])); /* second function */
}
void passByReference_inner(HEAD *c)
{
c->face = (c->face) + 1000;
c->nose = (c->nose) + 2000;
}
int main(void)
{
int i;
HEAD c[12]; /* you don't need static here (do you know what static is for?) */
for ( i = 0; i < 12; i++ )
{
c[i].face = i + 30;
c[i].nose = i + 60;
}
/*
* the element count of the array is sizeof(c) / sizeof(c[0])
* (totalSizeOfArray) / (indivudualElementSizeOfArray).
*/
passByReference(c, sizeof(c) / sizeof(c[0])); /* first function */
return 0;
}
what you should know is that arrays in c decay to a pointer that points to their first element when passed as parameters to functions.
Since you want to process all the structs in the second function, I don't see the need for the first function, anyway this is how you would do it then
#include <stdio.h>
struct card
{
int face;
int nose;
};
typedef struct card HEAD ;
/* prototype */
void passByReference(HEAD *const c, int count); /* first function */
void passByReference_inner(HEAD *const c, int count); /* second function */
void passByReference(HEAD *const c, int count)
{
passByReference_inner(c, count); /* second function */
}
/* HEAD *const c prevents the pointer c to be changed
* this way it will never point anywhere else.
*
* And you can be sure to alter the original data.
*/
void passByReference_inner(HEAD *const c, int count)
{
for (int i = 0 ; i < count ; ++i)
{
c[i].face = (c[i].face) + 1000;
c[i].nose = (c[i].nose) + 2000;
}
}
int main(void)
{
int i;
HEAD c[12]; /* you don't need static here (do you know what static is for?) */
for ( i = 0; i < 12; i++ )
{
c[i].face = i + 30;
c[i].nose = i + 60;
}
/*
* the element count of the array is sizeof(c) / sizeof(c[0])
* (totalSizeOfArray) / (indivudualElementSizeOfArray).
*/
passByReference(c, sizeof(c) / sizeof(c[0])); /* first function */
return 0;
}
since you are effectively passing a pointer, you alter it's contents directly in both functions the first and the second.
One more thing, you don't really need the static keyword, specially in main(), static keeps the value of the variable between function calls, and since main() will normally be called only once in the lifetime of the program... it doesn't make much sense to use static there.
Your second function is correct.
A pointer to the first element of an array is effectively the same thing as the pointer to an array itself.
What you should do is
void passByReference_inner(HEAD *c, size_t n)
{
}
So, you'll pass the pointer to the first element of the array, and the number of elements in the array, something like this:
passByReference(c, sizeof(c)/sizeof(c[0]));
This will pass the pointer to the first element of the c array, and the number of elements in the array, to passByReference_inner(). sizeof(c) is the size of the entire array in bytes. sizeof(c[0]) is the size of an element in the array. So, if, for example, each struct is 10 bytes long (just an example), and you have an array of 12 structs, the size of the entire array is 120 bytes, and this calculates the value 120/10=12, the number of elements in the array, automatically.
When you use the name of an array object, in C/C++ that automatically becomes a pointer to the first element of the array.
In your function, you can work with the array in the following manner:
void passByReference_inner(HEAD *c, size_t n)
{
for (size_t i=0; i<n; i++)
{
HEAD *p=c+i;
// p is now a pointer to the ith element of the array
}
}
Adding an integer n to a pointer advances the pointer to the next nth element of an array. Adding an integer value to a pointer doesn't advance the pointer by this number of bytes, but by the number of bytes in the object the pointer points to, multiplied by the number you're adding (or subtracting, same thing). That makes pointer arithmetic do the right thing.
The following code compiles cleanly.
The following code moves the increment values loop
to inside the passByReference() function.
/*
* Note: guard code is used in a header file
* so the header file can only be included once
* in each compilation unit
*/
// note the inclusion of a 'guard' wrapper
// begin: array_of_struct.h file
#ifndef ARRAY_OF_STRUCT_H
#define ARRAY_OF_STRUCT_H
struct card
{
int face;
int nose;
};
// dont obsecure the code with useless typedef statements
//typedef struct card HEAD ;
#define MAX_CARDS (12)
/* prototype */
extern void passByReference(struct card *pCards); /* first function */
extern void passByReference_inner(struct card *pCard); /* second function */
#endif
// end: array_of_struct.h
//first function: (passByReference), in different file
#include <stdio.h>
#include "array_of_struct.h"
void passByReference(struct card *pCards)
{
int i=0; // loop index
for(i=0;i<MAX_CARDS;i++)
{
passByReference_inner (&pCards[i]); /* second function */
} // end for
} // end function: passByReference
// second function: (passByReference_inner), in different file
#include <stdio.h>
#include "array_of_struct.h"
void passByReference_inner(struct card *pCard)
{
pCard->face = (pCard->face) + 1000;
pCard->nose = (pCard->nose) + 2000;
} // end function: passByReference_inner
//main, in a different file
#include <stdio.h>
#include "array_of_struct.h"
int main()
{
int i = 0; // loop index
static struct card cards[MAX_CARDS];
for ( i = 0; i < MAX_CARDS; i++ )
{
cards[i].face = i + 30;
cards[i].nose = i + 60;
} // end for
passByReference(&cards[0]); /* first function gets ptr to whole array*/
// could also be written as:
// passByReference(cards);
return 0;
} // end function: main
I've analyzed all three solutions (iharob, user3629249, Sam Varshavchik) and came to the conclusion that Sam Varshavchik and the second solution from iharob were right on the money. The first iharob's solution and user3629249 solution are, in essence, equal. They moved for loop from main to the first function. The second solution of the iharob's post matches the requirements from the initial post. Sam's solution gave me enough hints/instructions for 'how to move for loop from the main to the second function (which was, basically, what I did not know how to do it and therefore asked for help).
So, to make long story short, here is the source code which implements almost all suggestions from all contributors. The code compiles cleanly, so, beginners like me, can take it as-is and learn few details about pointer to pointer, pointer arithmetic and about array of structs.
array_of_struct.h (header file)
#ifndef ARRAY_OF_STRUCT_H
#define ARRAY_OF_STRUCT_H
/* HEAD structure definition */
typedef struct
{
int face;
int nose;
} HEAD; // end structure HEAD
#define MAX_HEADS (12)
/* prototype */
extern void passByReference(HEAD **c, size_t n);
extern void passByReference_inner(HEAD *c, size_t n);
#endif
passByReference.c (first function)
#include <stdio.h>
#include "array_of_struct.h"
void passByReference(HEAD **c, size_t n)
{
passByReference_inner (*c, n);
}
passByReference_inner.c (second function)
#include <stdio.h>
#include "array_of_struct.h"
void passByReference_inner(HEAD *c, size_t n)
{
int i;
HEAD *p;
printf("\nPOINTER ARITHMETIC: The value of struct's members after PASS BY REFERENCE \n");
for ( i = 0; i < n; i++ )
{
p = c + i;
p->face = (p->face) + 1000;
p->nose = (p->nose) + 2000;
printf("struct[%i].face = %d \n",i, p[0].face);
printf("struct[%i].nose = %d \n",i, p[0].nose);
}
printf("\nARRAY INDEX MATH: The value of struct's members after PASS BY REFERENCE\n");
printf("[NOTE: structs were updated in the for loop above]\n");
for ( i = 0; i < n; i++ )
{
printf("struct[%i].face = %d \n",i, c[i].face);
printf("struct[%i].nose = %d \n",i, c[i].nose);
}
}
main.c
#include <stdio.h>
#include "array_of_struct.h"
int main(void)
{
int i;
HEAD c[MAX_HEADS];
HEAD *cptr;
size_t n;
n = (sizeof(c) / sizeof(c[0]);
printf("\nINITIALIZATION of all struct's members\n");
for ( i = 0; i < n; i++ )
{
c[i].face = i + 30;
c[i].nose = i + 60;
printf("struct[%i].face = %d\n",i, c[i].face);
printf("struct[%i].nose = %d\n",i, c[i].nose);
}
cptr = &c[0];
passByReference(&cptr, n);
return 0;
}
Related
I am new in learning C. I have an issue in returning double star pointer from the function.
This is my code.
#include <stdio.h>
#include <stdbool.h>
#include "api.h"
void init() {
// You can initiate and calculate things here
}
/**
* Return the given list in reversed order. Each element in the given list contains a single character.
*
* typedef struct {
* int count;
* const char * * elements;
* } string_list;
*
* list_of_chars: string_list
*
* returns: string_list
*/
string_list reverse(string_list list_of_chars) {
// Write your code here
char X[list_of_chars.count];
//X[0] = *list_of_chars.elements[0];
for (int i = 0; i < list_of_chars.count;i++){
X[i] = *list_of_chars.elements[i];
}
printf("%c", X[0]);
string_list return_value = {
.count = 0,
.elements = &X[0],
};
return return_value;
}
But I am getting initialization of 'const char **' from incompatible pointer type 'char *'. I tried multiple solutions but non of them worked.
Side note: As I mentioned in the top comments, I was limited to what I could do on mobile. I'm back at my desk.
Issues were:
X is function scoped, so it goes out of scope when the function returns. We need to use malloc [so we need stdlib.h]
Because elements is a const char **, then we need const char **X
We need to use [should use] strdup to duplicate the elements.
Otherwise, both lists will share the same data. This may the desired intent. But, it's not clear from the problem description what the correct code should be.
Most lists should be fully independent from one another. The original code does not do this. So, the lists are sharing the data. But, if that's true, why bother to create a separate list? We could just "reverse" it by indexing in the reverse direction without creating a new list:
for (int i = list.count - 1; i >= 0; --i)
So, I've chosen to duplicate the strings. Original behavior (shared strings) when compiled with -DNODUP.
Here's the refactored code:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#if 0
#include "api.h"
#else
typedef struct {
int count;
const char **elements;
} string_list;
#endif
void
init()
{
// You can initiate and calculate things here
}
/**
* Return the given list in reversed order. Each element in the given list contains a single character.
*
* typedef struct {
* int count;
* const char * * elements;
* } string_list;
*
* list_of_chars: string_list
*
* returns: string_list
*/
string_list
reverse(string_list list)
{
const char **X = malloc(sizeof(*X) * list.count);
// share the strings
#if NODUP
for (int i = 0; i < list.count; i++)
X[list.count - 1 - i] = list.elements[i];
// make lists independent (more usual/expected)
#else
for (int i = 0; i < list.count; i++)
X[list.count - 1 - i] = strdup(list.elements[i]);
#endif
string_list ret = {
.count = list.count,
.elements = X,
};
return ret;
}
UPDATE:
In the link above was the exercise page where we can choose GCC for C. I pasted your code exactly to the website bit still see same errors.
Okay, finally ... ;-)
The website uses an ancient version of the C standard (e.g. C99). This does not have strdup.
The website will [forcibly] do a #include "api.h" before including the code, so there is a conflict with the definition I used.
Here is the corrected code (which runs successfully on the website):
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#if 1
#include "api.h"
#else
typedef struct {
int count;
const char **elements;
} string_list;
#endif
void
init()
{
// You can initiate and calculate things here
}
/**
* Return the given list in reversed order. Each element in the given list contains a single character.
*
* typedef struct {
* int count;
* const char * * elements;
* } string_list;
*
* list_of_chars: string_list
*
* returns: string_list
*/
string_list
reverse(string_list list)
{
const char **X = malloc(sizeof(*X) * list.count);
// share the strings
#if 1
for (int i = 0; i < list.count; i++)
X[list.count - 1 - i] = list.elements[i];
// make lists independent (more usual/expected)
#else
for (int i = 0; i < list.count; i++)
X[list.count - 1 - i] = strdup(list.elements[i]);
#endif
string_list ret = {
.count = list.count,
.elements = X,
};
return ret;
}
Side note: I'd get a good book on C and study that to get more basic knowledge of C. Trying to use "competition" websites isn't the best way, IMO.
A number of the issues you've seen (but did not understand) would have been obvious with a better basic understanding of C syntax and semantics.
Here's a list: The Definitive C Book Guide and List
Feel like im taking crazy pills just trying to do literally the simplest stuff I can imagine in C. Any help would be extremely appreciated. why does this work?
#include <stdio.h>
#include <stdlib.h>
#define Q_LIMT 100
typedef struct servers
{
int id;
int num_in_Q;
int server_status;
}SERVER;
void initialize(SERVER *s);
void initialize(SERVER *s)
{
int i=0,j=0;
for(i=0; i<2; i++) { //i=0; i=1
s[i].id = i; // 0, 1
s[i].num_in_Q = i*i + 1; // 1, 2
s[i].server_status = i+i + 2; // 2, 4
} // the bracket was missing
}
int main()
{
int i;
SERVER serv[2];
initialize(serv);
for(i=0; i<2; i++) {
printf("server[%d].id = %d\n", i, serv[i].id);
printf("server[%d].num_in_Q = %d\n", i, serv[i].num_in_Q);
but this throws away the initialized struct?
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
'''
int POINTERS_PER_INODE = 5;
struct Inode {
int valid;/* 0 == invalid, 1 == valid*/
int size;
int Blocks [5];
};
int InodeToString(char * InodeString, struct Inode iNode){
char * blockBuffer;
sprintf(InodeString, "%d", iNode.valid);
int i;
for (i = 0; i < POINTERS_PER_INODE; i++){
blockBuffer = malloc(8);
sprintf(blockBuffer, "%d", iNode.Blocks[i]); //no valid pointers yet
strcat(InodeString,blockBuffer);
free(blockBuffer);
}
return 0;
}
int initializeInode(struct Inode iNode){
int i;
for (i = 0; i < POINTERS_PER_INODE; i++){
iNode.Blocks[i] = -1; //no valid pointers yet
}
iNode.valid = 0; //initialized as invalid inode
return 0;
}
int main() {
struct Inode iNode1;
initializeInode(iNode1);
char * InodeString;
InodeString = malloc(20);
InodeToString(InodeString, iNode1);
printf("%s", InodeString);
free(InodeString);
iNode1.valid = 1;
InodeString = malloc(20);
InodeToString(InodeString, iNode1);
printf("%s", InodeString);
return 0;
}
This is test code btw, so the includes probably dont make sense. stack overflow says I dont have enough details so I guess I have to keep typing sentences. Let me know if theres any details that would make this more clear. its for a basic super simplified file system simulation project. it seemed in a previous version when I initialized the inode outside of the function, I was able to pass the string into the string function, assign it values, not use it as the return value and still end up on the other side of the function with an updated string.
As is normal in C, arguments to a function are passed by value. The object called iNode in initializeInode is local to that function, and changes to it have no effect on any other object in the program. If you want a function to modify an object that's local to the caller, you have to pass a pointer to it, and dereference that pointer to get at the caller's object.
So what you probably want is:
int initializeInode(struct Inode *iNode){
int i;
for (i = 0; i < POINTERS_PER_INODE; i++){
iNode->Blocks[i] = -1; //no valid pointers yet
}
iNode->valid = 0; //initialized as invalid inode
return 0;
}
int main() {
struct Inode iNode1;
initializeInode(&iNode1);
// ...
}
I can't figure out what I am doing wrong with my pointers. It is causing a segmentation fault. I am convinced the problem is rooted in my use of the array of pointers I have and the pthread_join I am using.
The goal is to read multiple integers into a gcc compiler, then print out the integer with all its factors, like this, 12: 2 2 3
I created a struct containing an int array to store the factors of each integer as the factor function pulls it apart and a counter(numfact) to store how many factors there are stored in the array.
I commented out the section at the bottom that prints out the factors.
I think the problem is how I am trying to store the output from the pthread_join in the pointer array, ptr[]. Whenever I comment it out, it does not get the segmentation error.
Either I have my pointers screwed up in a way I don't understand or I can't use an array of pointers. Either way, after many hours, I am stuck.
Please help.
#include <stdio.h>
#include <pthread.h>
#include <math.h>
#include <stdlib.h>
struct intfact
{
long int factors[100];
int numfact;
};
struct intfact *factor(long int y)
{
struct intfact threadfact;
threadfact.numfact = 0;
// Store in struct the number of 2s that divide y
while (y % 2 == 0)
{
threadfact.factors[threadfact.numfact] = 2;
threadfact.numfact++;
y = y/2;
}
// Store in struct the odds that divide y
for (int i = 3; i <= floor(sqrt(y)); i = i+2)
{
while (y % i == 0)
{
threadfact.factors[threadfact.numfact] = i;
threadfact.numfact++;
y = y/i;
}
}
// Store in struct the primes > 2
if (y > 2)
{
threadfact.factors[threadfact.numfact] = y;
threadfact.numfact++;
}
struct intfact *rtnthred = &threadfact;
return rtnthred;
}
/* Trial Division Function */
void *divde(void *n)
{
long int *num = (long int *) n;
struct intfact *temp = factor(*num);
return temp;
}
/* Main Function */
int main(int argc, char *argv[])
{
pthread_t threads[argc-1];
void *ptr[argc-1];
/* loop to create all threads */
for(int i=0; i < argc; i++)
{
long temp = atol(argv[i+1]);
pthread_create(&threads[i], NULL, divde, (void *) temp);
}
/* loop to join all threads */
for(int i=0; i < argc; i++)
{
pthread_join(threads[i],(void *) ptr[i]); //THIS POINTER IS THE PROBLEM
}
/* loops to print results of each thread using pointer array*/
//for(int i = 0; i < argc; i++)
//{
// printf("%s: ", argv[i+1]); /* print out initial integer */
// struct intfact *temp = (struct intfact *) ptr[i]; //cast void pointer ptr as struct intfact pointer
// printf("%d", temp->numfact);
//for(int j = 0; j < temp->numfact; j++) /*(pull the numfact(count of factors) from the struct intfact pointer??)*/
//{
// printf("%d ", temp->factors[j]); /* print out each factor from thread struct */
//}
}
}
In my Linux) terminal this code is stored in p3.c
"./p3 12" should yeild "12: 2 2 3"
For starters:
Here
long temp = atol(argv[i+1]);
pthread_create(&threads[i], NULL, divde, (void *) temp);
you define a long int and pass it as argument to the thread. For example 12
Inside the thread function then
void *divde(void *n)
{
long int *num = (long int *) n;
you treat the long int passed in as pointer to long int.
And then here dereference it
... = factor(*num);
So this *num for example would become *12. That is referencing memory address 12 to read out its content and pass it to factor). Aside the fact that this mostly likely is an invalid address, there would be nothing relevant store, at least nothing your code defined.
To (more or less fix) this do
void *divde(void *n)
{
long int num = (long int) n;
... = factor(num);
The second issues is mentioned in the comment: Multiple threads to find prime factors of integers, segmentation fault
The problem you are trying to solve is a special case of parallel programming, namely that the tasks to be run in parallel are completely independent. In such cases it makes sense to give each task its own context. Here such a context would include the
thread-id,
the thread specific input
as well as its specific output.
In C grouping variables can be done using structures, as your implementation already comes up with for the output of the tasks:
struct intfact
{
long int factors[100];
int numfact;
};
So what is missing is thread-id and input. Just add those for example like this.
/* group input and output: */
struct inout
{
long int input;
struct intfact output;
};
/* group input/output with thread-id */
struct context
{
pthread_t thread_id;
struct inout io;
};
Now before kicking off the threads define as many contexts as needed:
int main(int argc, char *argv[])
{
size_t num_to_process = argv - 1;
struct context ctx[num_to_process];
then create the threads passing in what is needed, that is input along with space/memory for the output:
for (size_t i = 0; i < num_to_process ; i++)
{
ctx[i].io.input = atol(argv[i]);
pthread_create(&ctx[i].thread_id, NULL, divide, &ctx[i].io);
}
Inside the thread function convert the void-pointer received back to its real type:
void *divide(void * pv)
{
struct inout * pio = pv; /* No cast needed in C. */
Define the processing function to take a pointer to the context specific input/output variables:
void factor(struct inout * pio) /* No need to return any thing */
{
/* Initialise the output: */
pio->output.numfact = 0;
/* set local copy of input: */
long int y = pio->input; /* One could also just use pio->input directly. */
Replace all other occurrences of threadfact by pio->output.
Use
return;
}
to leave the processing function.
Then inside the thread function call the processing function:
factor(pio);
Use
return NULL;
}
to leave the thread function.
In main() join without expecting any result from the threads:
/* loop to join all threads */
for (size_t i = 0; i < num_to_process; i++)
{
pthread_join(ctx[i].thread_id, NULL);
}
Putting this all together:
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <math.h>
struct intfact
{
long int factors[100];
size_t numfact;
};
/* group input and output: */
struct inout
{
long int input;
struct intfact output;
};
/* group input/output with thread-id */
struct context
{
pthread_t thread_id;
struct inout io;
};
void factor(struct inout * pio)
{
/* Initialise the output: */
pio->output.numfact = 0;
/* set local copy of input: */
long int y = pio->input; /* One could also just use pinout->input directly. */
if (0 == y)
{
return; /* Nothing to do! */
}
// Store in struct the number of 2s that divide y
while (y % 2 == 0)
{
pio->output.factors[pio->output.numfact] = 2;
pio->output.numfact++;
y = y/2;
}
// Store in struct the odds that divide y
for (int i = 3; i <= floor(sqrt(y)); i = i+2)
{
while (y % i == 0)
{
pio->output.factors[pio->output.numfact] = i;
pio->output.numfact++;
y = y/i;
}
}
// Store in struct the primes > 2
if (y > 2)
{
pio->output.factors[pio->output.numfact] = y;
pio->output.numfact++;
}
return;
}
void *divide(void * pv)
{
struct inout * pio = pv; /* No cast needed in C. */
factor(pio);
return NULL;
}
int main(int argc, char *argv[])
{
size_t num_to_process = argc - 1;
struct context ctx[num_to_process];
for (size_t i = 0; i < num_to_process; i++)
{
ctx[i].io.input = atol(argv[i+1]);
if (!ctx[i].io.input)
{
fprintf(stderr, "COnversion to integer failed or 0 for '%s'\n", argv[i]);
}
pthread_create(&ctx[i].thread_id, NULL, divide, &ctx[i].io);
}
/* loop to join all threads */
for (size_t i=0; i < num_to_process; i++)
{
pthread_join(ctx[i].thread_id, NULL);
}
/* loops to print results of each thread using pointer array*/
for(size_t i = 0; i < num_to_process; i++)
{
printf("%ld: ", ctx[i].io.input); /* print out initial integer */
printf("%zu factors --> ", ctx[i].io.output.numfact);
for(size_t j = 0; j < ctx[i].io.output.numfact; j++)
{
printf("%ld ", ctx[i].io.output.factors[j]); /* print out each factor from thread struct */
}
putc('\n', stdout);
}
}
I am trying to use qsort to sort a struct containing pointers. Is the problem with the comparison function? How do I fix so I can sort based on the cc.
Here is the code:
#include <stdlib.h>
#include <string.h>
typedef enum {
PETROL,
DIESEL,
ELECTRIC,
LPG,
BIOFUEL,
OTHER
} fuel_t;
typedef struct car_tag {
unsigned cc;
fuel_t fueltype;
} car_t;
typedef struct fleet_tag {
car_t ** cars;
size_t n_cars;
} fleet_t;
int car_comp(const void * vp1, const void * vp2) {
const car_t* const c1 = vp1;
const car_t* const c2 = vp2;
if (c1->cc > c2->cc)
return -1;
else if (c1->cc < c2->cc)
return 1;
else {
return 0;
}
}
int main() {
car_t array[] = {
{ 600, PETROL},
{1200, PETROL},
{1000, PETROL},
{1600, DIESEL},
{1000, ELECTRIC}
};
int size = sizeof(array) / sizeof(array[0]);
fleet_t fl;
fl.n_cars = size;
fl.cars = malloc(size * sizeof(car_t));
for (int i = 0; i < size; i++) {
car_t* pc = malloc(sizeof(car_t));
memcpy(pc, &array[i], sizeof(car_t));
fl.cars[i] = pc;
}
// how to sort cars by cc
qsort(&fl, fl.n_cars, sizeof(car_t), car_comp);
// sort function doesn't correctly sort fleet of cars by cc
}
I don't see the need for the dynamic allocation and memcpy invoke for each to-be-sorted car in this code at all.
You're building a pointer bed (a sequence of pointers) so why not just allocate that (which you're doing), and then store the addresses of each element from array there. Then, tailor your comparator to address what you're sending: an address of a pointer (pointer to pointer) and setup the dereferences accordingly
Add to that, you should be passing fl.cars to qsort, not &fl, and the sizeof argument therein is also wrong.
Finally, I don't know if you intentionally wanted to use a greater-than logic stack in your comparator, but that is exactly what you ended up with.
Example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef enum {
PETROL,
DIESEL,
ELECTRIC,
LPG,
BIOFUEL,
OTHER
} fuel_t;
typedef struct car_tag {
unsigned cc;
fuel_t fueltype;
} car_t;
typedef struct fleet_tag {
car_t ** cars;
size_t n_cars;
} fleet_t;
int car_comp(const void * vp1, const void * vp2)
{
const car_t * const *pc1 = vp1;
const car_t * const *pc2 = vp2;
if ((*pc1)->cc > (*pc2)->cc)
return -1;
if ((*pc1)->cc < (*pc2)->cc)
return 1;
return 0;
}
int main() {
car_t array[] = {
{ 600, PETROL},
{1200, PETROL},
{1000, PETROL},
{1600, DIESEL},
{1000, ELECTRIC}
};
int size = sizeof(array) / sizeof(array[0]);
fleet_t fl;
fl.n_cars = size;
fl.cars = malloc(size * sizeof *fl.cars);
for (int i = 0; i < size; i++)
fl.cars[i] = array+i;
// how to sort cars by cc
qsort(fl.cars, fl.n_cars, sizeof *fl.cars, car_comp);
for (int i=0; i<size; ++i)
printf("%d (%u, %d)\n", i+1, fl.cars[i]->cc, fl.cars[i]->fueltype);
free(fl.cars);
return EXIT_SUCCESS;
}
Output
1 (1600, 1)
2 (1200, 0)
3 (1000, 0)
4 (1000, 2)
5 (600, 0)
qsort works by feeding it a sequence of "things", a length stating how many "things" there are, a size noting how big each "thing" in the sequence is, and finally a comparator function which will be fed the address of each "thing" during execution of the algorithm.
In your case, your "things" are pointers to car_t structures. In fact,
Your sequence is a dynamic array of pointers; your "thing" is a pointer to a car_t.
You length is size.
Your size of each "thing" is the size of a pointer.
Your comparator will access the address of two of your things (therefore, two pointers, so pointers to pointers), and act accordingly.
Therefore, the call becomes:
qsort(fl.cars, fl.n_cars, sizeof *fl.cars, car_comp);
Finally, note that the original array remains unchanged. The sort modified your pointer bed only. That was probably desirable, and I hope you understand how it works.
I using first time the HEADERS in c so I'm not understanding it well.
main.c
#include <stdio.h>
#include <stdlib.h>
#include "kibe.h"
int main()
{
int a[5],n,i;
beolvas(a,n,"be.txt");
kiir(a,n);
return 0;
}
kibe.h
#ifndef KIBE_H_INCLUDED
#define KIBE_H_INCLUDED
void beolvas(int*, int, const char *);
void kiir(int*, int);
#endif // KIBE_H_INCLUDED
kibe.c
#include <stdio.h>
#include <stdlib.h>
void beolvas(int *a,int n,const char * file)
{
int i;
FILE * fin;
fin = fopen("be.txt", "rt");
fscanf(fin,"%i",&n);
a = (int*)malloc(n*sizeof(int));
for(i = 0; i < n; ++i){
fscanf(fin,"%i",&a[i]);
}
free(a);
}
void kiir(int *a,int n)
{
int i;
for(i = 0; i < n; ++i){
printf("%i ",a[i]);
}
}
The problem is that I get memory garbage every time and the file contains five numbers which must be read and written to monitor. If I write the void kiir is code to void beolvas function it works well.
You allocate dynamic memory in your function beolvas but you never pass it out of the function. Your parameters a and n have to be output parameters, so you have to change your function signature. Apart form this use fclos to close the file. Adapt your code like this:
kibe.c
void beolvas( int **a, int *n, const char * file )
// ^^ ^ output paramters a and n
{
FILE * fin;
fin = fopen("be.txt", "rt");
fscanf( fin, "%i", n ); // read number of elements
// ( n is a pointer to an int )
*a = malloc( *n * sizeof(int) ); // allocate memors
for ( int i = 0; i < n; ++i)
{
fscanf(fin,"%i",(*a)+i); // read one element
// ( *a is the pointer to the dynamic memory,
// so (*a)+i is a pointer to (*a)[i] )
}
fclose(fin);
}
kibe.h
void beolvas( int**, int* , const char *);
main.c
int main()
{
int a* = NULL;
int n = 0;
beolvas( &a, &n,"be.txt");
// ^ ^
kiir( a, n );
free(a); // free the memory which was allocated inside function beolvas
return 0;
}