So, my first question here, please be patient with me:
My task is to sort an array of structs (name, surname and another struct for the birthday, which consists of the year, month, day). I have to sort by birthdate and by using qsort.
My problem is, I looked up everything about qsort but i am not quite sure if my implementation is correct since I am new to C. I can create the executable program but it is not giving my any result only Segmentation Fault.
Here is my Code:
#include <stdio.h>
#include <stdlib.h>
typedef int (*compfn) (const void*, const void*);
typedef struct {
unsigned year, month, day;
} date_t;
typedef struct {
char name[32];
char surname[32];
date_t birthday;
}person_t;
typedef struct {
unsigned n;
unsigned cap;
person_t *arr;
} persons_t;
int compare(person_t *a, person_t *b){
if(a->birthday.year!=b->birthday.year){
return a->birthday.year-b->birthday.year;
}else{
if(a->birthday.month!=b->birthday.month){
return a->birthday.month-b->birthday.month;
}else{
return a->birthday.day-b->birthday.day;
}
}
}
int main(int argc, char* argv[])
{
if (argc <= 1) {
fprintf(stderr, "syntax: %s <inputfile>\n", argv[0]);
return 1;
}
FILE* f = fopen(argv[1], "rt");
if (f == NULL) {
fprintf(stderr, "cannot open file %s\n", argv[1]);
return 1;
}
persons_t persons;
persons.n = 0;
persons.cap = 0;
persons.arr = NULL;
person_t p;
while (fscanf(f, "%s %s %4u-%2u-%2u", p.name, p.surname,
&p.birthday.year, &p.birthday.month, &p.birthday.day) == 5) {
if (persons.n == persons.cap) {
persons.cap = persons.cap == 0 ? 1 : 2 * persons.cap;
persons.arr = realloc(persons.arr, persons.cap * sizeof(persons.arr[0]));
}
persons.arr[persons.n++] = p;
}
int nitems = persons.cap*sizeof(persons.arr[0]);
int size = sizeof(persons.arr[0]);
qsort(persons.arr, nitems, size, (compfn)compare);
for (unsigned i = 0; i < persons.n; i++) {
person_t *p = persons.arr + i;
printf("%s %s %4u-%2u-%2u\n",
p->name, p->surname,
p->birthday.year, p->birthday.month, p->birthday.day);
}
fclose(f);
return 0;
}
I hope someone can help me,
Thanks in advance ;)
As far as _t-suffixed identifiers go, according to the C standard they're reserved for the implementation (e.g. your compiler, and/or your standard library). It's very possible that your implementation already has a date_t type, and your code might be causing some kind of mischief. If you wish to avoid subtly and dangerously clashing identifiers wreaking all sorts of havoc, it's probably best to avoid them. Not to worry, you could always use '_s' to denote a struct type instead!
Whenever you're declaring a variable that represents an index within an array, use size_t as the type!
int compare(person_t *a, person_t *b){
...
qsort(persons.arr, nitems, size, (compfn)compare);
According to the qsort manual, the argument given as the comparator function should be an int (*compar)(const void *, const void *), and that's what you've given since you've cast to (compfn). As far as qsort is aware that function accepts two const void * arguments, which might differ in representation to person_t * arguments. This could certainly cause segfaults. Don't lie about the type of compare. Change it to look more like:
int compare(const void *x, const void *y) {
const person_s *a = x, *b = y;
/* ... */
}
... and you won't need the cast or the typedef.
Next, onto return values for that function. I have used implementations where-by lexically illogical return values cause segmentation faults. For example, if a <= b and b <= c, then a <= c, but your code doesn't guarantee this. In fact, using your code it is possible that a <= b, b <= c and a > c. I recommend making sure your code guarantees correspondence between the return value and lexical order. You can do so by returning 1 for greater than, 0 for equal to or -1 for less than.
#define lexical_order(x,y) ((x > y) - (x < y))
int compare(const void *x, const void *b){
const person_s *a = x, *b = y;
return a->birthday.year != b->birthday.year ? lexical_order(a->birthday.year, b->birthday.year)
: a->birthday.month != b->birthday.month ? lexical_order(a->birthday.month, b->birthday.month)
: lexical_order(a->birthday.day, b->birthday.day);
}
I'm sure you're aware that you should be checking the return value of realloc... For example:
void *temp = realloc(persons.arr, persons.cap * sizeof(persons.arr[0]));
if (temp == NULL) { /* If we don't check return value prior *
* to assigning to persons.arr, we *
* might leak some memory... */
puts("Error in realloc");
free(persons.arr);
exit(-1);
}
persons.arr = temp;
Finally, and most importantly (this is probably your error), are you sure about this?
int nitems = persons.cap*sizeof(persons.arr[0]);
If you mean to pass this as the number of items to qsort (which is usual), then I think that should be:
size_t nitems = persons.n;
P.S. In case you missed it the second time, you should probably audit your code to make sure you're using size_t to store array indexes only.
P.P.S. Don't forget to free(persons); at the end of your program, so you don't end up with reports of memory leaks when you use valgrind...
P.P.P.S. valgrind is awesome!
So you are allocating our array by doubling its size whenever needed, using persons.cap, but you are not filling all its elements, are you?
From your code, the actual number of persons is nitems = persons.n, not persons.cap. What if you retry your code with nitems=persons.n?
If you have unfilled elements in your array, it means the strings inside them are arbitrary (i.e person.name), so probably not null-terminated, and the crash will occur when you try to display them.
Related
So when I pass a data type like a struct to assign some memory to it I find that the pointer doesn't change within the main scope. This further becomes a problem when I try to free the memory but obviously if its using the original pointer it will be pointing at the stack address.
void allocate(int *value){
value = malloc(10 * sizeof(int));
}
int main(){
int val2;
allocate(&val2);
free(&val2);
return 0;
}
I can fix this by using a double pointer to be passed into the allocate function but some course work I'm doing requires to only pass a pointer and I cant get it to update the pointer when it returns to main. I have looked around for a while but cant find a straight forward answer, I feel like my coursework is wrong but that might be my lack of understanding.
The requirement to "only pass a pointer" seems contrived, and you could argue that a pointer to pointer (not a "double pointer") is a pointer, but perhaps you could use void * to punch a hole in the type system. Or use a struct:
#include <stdlib.h>
#include <stdio.h>
struct intbuffer {
int *d;
size_t cap;
};
void *
xmalloc(size_t s)
{
void *r = malloc(s);
if( r == NULL ){
perror("malloc");
exit(1);
}
return r;
}
void
allocate(void *p, size_t s)
{
*(int **)p = xmalloc(s * sizeof(int));
}
void
allocate2(struct intbuffer *p)
{
p->d = xmalloc(p->cap * sizeof *p->d);
}
int
main(void)
{
int *val2;
struct intbuffer v;
allocate(&val2, 10);
free(val2);
v.cap = 10; /* Horrible api!! */
allocate2(&v);
free(v.d);
return 0;
}
Note that setting the capacity in the struct prior to making the call to allocate is a violation of many principles of software design, but this whole thing is absurdly contrived due to the bizarre artificial limitations.
There are not enough *'s in each place, but you will have to figure out what that means.
void allocate(int** value){
*value = malloc(10 * sizeof(int));
}
int main(){
int* val2;
allocate(&val2);
free(val2);
return 0;
}
In my notes the following code is provided as an example of a programm to allocate and deallocate
memory that doesn't work because the vett variable in the allocate function is local. The function is fixed by using a double pointer and doing the changes in the commented code
void allocate(double *vett, int n) //void allocate(double **vett, int n);
{ printf("vett=%p\n",vett); // printf("vett=%p\n",*vett);
vett = (double*)calloc(n,sizeof(double)); //*vett = (double*)calloc(n,sizeof(double));
printf("vett=%p\n",vett); // printf("vett=%p\n",*vett);
}
void freeit(double *vett) { free(vett); }
int main(int argc,char **argv)
{
double *v=NULL;
int i, size=atoi(argv[1]);
allocate(v,size); // allocate(&v,size);
printf("v=%p\n",v); //printf("v=%p, &v=%p\n",v,&v);
for(i=0;i<size;i++)
v[i]=i;
for(i=0;i<size;i++)
printf("v[%d]=%f\n",i,v[i]);
freeit(v);
return 0;
}
My question is do we really need a double pointer to fix the code? I came up with the following solution:
void* allocate(double *vett, int n) // I changed here
{ printf("vett=%p\n",vett);
vett = (double*)calloc(n,sizeof(double));
printf("vett=%p\n",vett);
return vett; // I added this
}
void freeit(double *vett) { free(vett); }
int main(int argc,char **argv)
{
double *v=NULL;
int i, size=atoi(argv[1]);
v=allocate(v,size); // I changed here
printf("v=%p\n",v);
for(i=0;i<size;i++)
v[i]=i;
for(i=0;i<size;i++)
printf("v[%d]=%f\n",i,v[i]);
freeit(v);
return 0;
}
Is my solution ok? If it is, is any of the solutions preferable over the other?
Additionaly in the following site https://aticleworld.com/dangling-pointer-and-memory-leak/ I found the following functions, but I don't think the Memory_Allocate function is correct, since it returns a local variable ( pvHandle). Am I right?
static unsigned int Allocate_Counter = 0;
static unsigned int Deallocate_Counter = 0;
void *Memory_Allocate (size_t size)
{
void *pvHandle = NULL;
pvHandle = malloc(size);
if (NULL != pvHandle)
{
++Allocate_Counter;
}
else
{
//Log error
}
return (pvHandle);
}
void Memory_Deallocate (void *pvHandle)
{
if(pvHandle != NULL)
{
free(pvHandle);
++Deallocate_Counter;
}
}
int Check_Memory_Leak(void)
{
int iRet = 0;
if (Allocate_Counter != Deallocate_Counter)
{
//Log error
iRet = Memory_Leak_Exception;
}
else
{
iRet = OK;
}
return iRet;
}
Your second example is correct, in the case you return back a pointer, that pointer is the one received from calloc(). And in that case there's no need for the double pointer. In the first case, without returning the pointer with return, the problem is that the pointer you pass to the function is copied in, and the copy can be modified inside the function, but that copy is different than the value of the variable you got it from.
Now two hints:
I have told you this in a comment to the question but: NEVER cast the result of malloc() and friends. You hide several possible errors if you cast the value returned: if you forget to #include <stdlib.h> the compiler will assume the function returns an int (wrongly, a pointer and a int are not the same size in 64bit architectures, and getting a 32 bit value will truncate your data to 32 bits, to later extend it to 64) and will generate code for getting an int that will be converted to a pointer (because of the cast, wrong again) with no warning from the compiler (because you have said with the cast don't worry, I know what I'm doing)
You return a void * from your function, which returns the value of a variable that is of type double *, and do so without a cast, that illustrates how the void * can be automatically converted by the compiler, so making the cast from malloc() totally unnecessary. But why don't return instead a double *, as you have already made the effort to convert a void * into a double *, just to convert it back to void *. If you want a wrapper function to return arrays of doubles, then return a double * in the function, and then you'll avoid the type conversion you do in the return statement, just to convert it again back to double * (which I guess this is what you want).
This applied to your code results in these comments:
/* return void *? Why did you convert it to double *? */
void* allocate(double *vett, int n)
/* why pass a pointer if you are not using the value inside the function body? */
{ printf("vett=%p\n",vett); /* well you print it :$ */
/* don't cast the automatic conversion, let the compiler do its work */
vett = (double*)calloc(n,sizeof(double));
printf("vett=%p\n",vett);
return vett; /* the double * stored in vett is converted to a void * to return it */
}
void freeit(double *vett) { free(vett); }
int main(int argc,char **argv)
{
double *v=NULL;
int i, size=atoi(argv[1]);
v=allocate(v,size); /* and you convert it again to double * here */
printf("v=%p\n",v);
...
so you get a void *, cast it to double * to be stored in a pointer variable, convert it to void * again to return the value to main and convert it again automatically to store it in main's v variable. My conclusion from this sample is that you never cast the value of malloc, and you should use the type void * as low as possible. The standard library functions do it for reasons out of scope, and trying to emulate them is something you can try, but when you have a better understanding of pointers. Until then, better never use void * pointers. A general principle is that you should the proper types, you never had to cast them. Casting should not be necessary (and it's almost never done in well written code) so better avoid casting as much as you can. The 80% of the errors come from bad casts, and the other 20% come from improperly defined types. C is already a language too lazy in type management, don't make it more by overusing of casts.
In my opinion, your code should be:
double *allocate_doubles(int n)
{
/* automatic conversion is done here only */
double *vett = calloc(n, sizeof(double));
printf("vett=%p\n", vett);
/* no conversion as vett is already of the function return type */
return vett;
}
void freeit(double *vett)
{
free(vett);
}
int main(int argc, char **argv)
{
double *v = NULL; /* use spaces, for readability */
int i, /* this is more readable */
size = atoi(argv[1]);
/* and no conversion because both, allocate and v are the same type */
v = allocate(v, size);
printf("v=%p\n", v);
for(i = 0; i < size; i++)
v[i] = i;
for(i = 0; i < size; i++)
printf("v[%d]=%f\n", i, v[i]);
freeit(v);
return 0;
}
In the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char** tab;
int n;
}slist;
void print(slist* p);
void add(slist* p, const char* s);
void add(slist* p, const char* s)
{
if(p->n==0)
{
p->tab=(char**)malloc(sizeof(char**));
}
strcpy(p->tab[p->n],s);
p->n=p->n+1;
}
void print(slist* p)
{
int i;
printf("[");
for(i=0;i<p->n;i++)
printf(" %s",p->tab[i]);
printf(" ]");
}
int main()
{
char s1[25] = "Picsou";
char s2[25] = "Flairsou";
slist* p = (slist*)malloc(sizeof(slist));
p->n=0;
p->tab=NULL;
add(p,s1);
add(p,s2);
print(p);
return 0;
}
the function add() doesn't work, but if I change it to:
void add(slist* p, const char* s)
{
if(p->n==0)
{
p->tab=(char**)malloc(sizeof(char**));
}
p->tab[p->n]=s;
p->n=p->n+1;
}
it seems to work perfectly well. In the first case the output is only " [";
in the second case it is what is should be: " [ Picsou Flairsou ] ".
I cannot understand why.
I also tried this :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char** tab;
int n;
}slist;
void print(slist* p);
void add(slist* p, const char* s);
void print(slist* p)
{
int i;
printf("[");
for(i=0;i<p->n;i++)
printf(" %s",p->tab[i]);
printf(" ]");
}
void add(slist* p, const char* s)
{
slist* tmp = (slist*)malloc(sizeof(slist));
tmp->tab=(char**)malloc(sizeof(char*)*(p->n+1));
int i;
for(i=0;i<p->n;i++)
tmp->tab[i]=(char*)malloc(sizeof(char));
strcpy(tmp->tab[p->n],s);
tmp->n=p->n+1;
p = tmp;
}
int main()
{
char* s1 = "Picsou";
char* s2 = "Flairsou";
slist* p = (slist*)malloc(sizeof(slist));
p->n=0;
p->tab=NULL;
add(p,s1);
add(p,s2);
print(p);
return 0;
}
Lots of errors here, which is common with people who are new to dealing with pointers. Where to begin... I'll just go in the order things appear in code.
This is not a "list".
It's an array... sort of. If you say "list" to a C programmer, they will think you mean a linked-list.
Incorrect allocation of array.
if(p->n==0)
{
p->tab=(char**)malloc(sizeof(char**));
}
Here you have allocated enough to store a single pointer. The second time you call add, you're going to access memory off the end. You have also incorrectly cast the result (in C, you don't cast the return value from malloc). Additionally, you have given confusing information to the reader, because you intend to allocate an array that will hold elements of type char*, NOT char**.
You must either allow the array to expand dynamically when required (not appropriate for your abilities right now - maybe try that in a few days), or set a maximum size. Let's do that.
const int MAX_SIZE = 100;
if( p->n==0 )
{
p->tab = malloc( MAX_SIZE * sizeof(char*) );
}
else if( p->n == MAX_SIZE )
{
printf( "Maximum size exceeded!\n" );
return;
}
You could use calloc instead of malloc if you like. It will zero-initialise the block after allocating it: calloc( MAX_SIZE, sizeof(char*) )
Copying to an uninitialized pointer.
strcpy(p->tab[p->n],s);
You allocated memory for tab, but you did not allocate memory that is pointed to by its elements, and here you have undefined behaviour (most likely resulting in a segmentation fault, but could do anything).
Make sure you have a valid pointer, and the location it points has enough storage reserved for the data you are copying into it:
p->tab[p->n] = malloc( strlen(s) + 1 );
strcpy( p->tab[p->n], s );
Storing potentially invalid pointer.
Your alternative that "works perfectly well" uses:
p->tab[p->n]=s;
However, the only reason this works is because those pointers remain valid for the whole time that you use the "list" (but actually the program does not "work" because of reasons I highlighted in number 2.
Sometimes we desire this behaviour in a program, and design our data structures to index pointers that they do not own. But more often, and especially for a beginner, you are better off copying the data (instead of simply copying the pointer). And so you'll instead use the approach I've suggested in number 3 above.
No comment!!
There are so many things wrong with the following code, that I'm not going to pull it apart or explain them.
void add(slist* p, const char* s)
{
slist* tmp = (slist*)malloc(sizeof(slist));
tmp->tab=(char**)malloc(sizeof(char*)*(p->n+1));
int i;
for(i=0;i<p->n;i++)
tmp->tab[i]=(char*)malloc(sizeof(char));
strcpy(tmp->tab[p->n],s);
tmp->n=p->n+1;
p = tmp;
}
However, it appears like you were attempting to do something similar to realloc. This is the option I mentioned in number 2 that I said you're maybe not ready for. But read up on it anyway: realloc
I wrote a function to compare 2 strings, return int as compare result, and pass an additional int pointer as param to retrieve the max match lengh.
// compare 2 strings
#include <stdio.h>
/**
* compare 2 string,
*
* #param sa
* string 1
* #param sb
* string 2
* #param len
* a int pointer pass from outside to store match length,
*
* return
* 0 if equlas, <0 if (a < b), >0 if (a > b),
*/
static int strCompare (char *sa, char *sb, int *len) {
for((*len)=0; *sa==*sb; sa++,sb++, (*len)++) {
// handle equals case, prevent ++ for \0,
if(!*sa)
break;
// printf("%c,%c\n", *sa, *sb);
}
return *sa - *sb;
}
int main(int argc, char *argv[]) {
if(argc < 3) {
printf("need 2 arguments.\n");
return 0;
}
int matchLen = 0;
int result = strCompare(argv[1], argv[2], &matchLen);
printf("compare:\n\t%s\n\t%s\nresult: %d\nmatch length: %d\n", argv[1], argv[2],
result, matchLen);
return 0;
}
Question:
I want the loop be more brief, e.g. avoid the if inside for, but didn't found out by myself, can anyone help to write a brief version with the same function interface.
(Please don't use libc function, I do this to improve my code style ;)
You might want to avoid the repeated reads and writes through the pointer while you are at it, and go for const-correctness:
static int strCompare (const char *sa, const char *sb, int *len) {
int tlen = 0;
while(*sa && *sa == *sb)
++tlen, ++sa, ++sb;
*len = tlen;
return *sa - *sb;
}
Or maybe better with restrict:
static int strCompare (const char *sa, const char *sb, int * restrict len) {
*len = 0;
while(*sa && *sa == *sb)
++*len, ++sa, ++sb;
return *sa - *sb;
}
BTW: The only thing making the code more efficient in the first case is avoiding the repeated writes through len.
In the second, it's using restrict and thus reducing aliasing (which will also remove all but the last write).
Also, consider whether size_t would not be a better type for the length.
Perhaps something like:
static int str_compare(const char *a, const char *b, size_t *len) {
const char *p = a;
for ( ; *p && *p == *b; ++p, ++b)
;
*len = p - a;
return *p - *b;
}
As Duplicator has mentioned use const for input strings.
Also size_t is widely used for sizes and counts, so likely better.
Alternative by tracking length:
static int str_compare(const char *a, const char *b, size_t *n) {
for (*n = 0; a[*n] && a[*n] == b[*n]; ++*n)
;
return a[*n] - b[*n];
}
Does not look too good with all the indirection on n, but still.
As a side note; you should return 1 (or something other then 0) on error (in main).
In your code if condition is needed. Because you are checking the pointer. If you accessing the pointer that is not allocate that will give you a segmentation fault. So avoid this you
have to do the if condition. Or else you can made that in the for loop.
for((*len)=0; *sa==*sb && *sa!='\0' ; sa++,sb++, (*len)++);
So avoiding the segmentation fault you need the another condition for checking.
I'm trying to create a structure storing strings and I'm getting an error incompatible types when I try and insert as string into the array. This my first time working with a program in C. Could somebody help spot my problem.
This is my implementation of list.c
struct list *init_list(int num) {
struct list *p;
p = malloc(LISTSZ(num));
if(p == NULL)
return(NULL);
p->maxsz = num;
p->sz = 0;
return(p);
}
void debug_list(struct list *p) {
int i;
fprintf(stderr, "\nDynamic List\n\n");
fprintf(stderr, " sz = %d\n", p->sz);
fprintf(stderr, " maxsz = %d\n", p->maxsz);
for(i = 0; i < p->maxsz; i++)
fprintf(stderr," %s\n", (p->item[i]));
}
void prt_list(struct list *p) {
int i;
for(i = 0; i < p->sz; i++)
printf("%s\n", (p->item[i]));
}
int ins_list(char *data, struct list **p) {
struct list *q;
if((*p)->sz == (*p)->maxsz) {
q = realloc(*p, LISTSZ((*p)->maxsz + INCRSZ)); // Problem?
if(q == NULL)
return(-1);
q->maxsz += INCRSZ;
*p = q;
}
(*p)->item[(*p)->sz] = data; // incompatible types in assignment
(*p)->sz ++;
return(0);
}
This is my implementation of list.h
struct list {
int sz;
int maxsz;
char item[][1024]; // Problem?
};
#define INITSZ 5
#define INCRSZ 5
#define LISTSZ(n) ((size_t)(sizeof(struct list) + ((n)-1)*sizeof(char[1024]))) // Problem?
struct list *init_list(int num);
int ins_list(char *data, struct list **p);
void prt_list(struct list *p);
void debug_list(struct list *p);
You have an array of char, yet you're trying to put a char * into it.
I would guess that strncpy will do what you want. Alternatively, declare item as an array of char *.
struct list {
int sz;
int maxsz;
char *item[1024];
};
There more differences between C and C++ than it's commonly admit.
For your error the reason is simple you are trying to assign a pointer (char*) at sz wich is an int.
This kind of assignment generate the incompatible type warning.
Second thing you can't do (a least as far as i know) a partially dynamic array as you do it. In your case you should use at least a malloc and the type of item should be char**. However there is a trick to use only one malloc to create a 2D array.
For the realloc nothing hit me ... What is the compilation error ?
However your code doesn't looks like C code :/
You might need to rebuild it form scratch, because you are here making confusion between lists and 2D arrays ...
I can write some examples of codes if you want but you should probably find a C basics tutorial on google.
Good luke :)
At this line:
(*p)->item[(*p)->sz] = data; // incompatible types in assignment
(*p)->item[(*p)->sz] is an array of 1024 char - you can't assign to arrays with = (arrays are "non-modifiable lvalues").
You just need to do a copy. For a length-safe string copy, I prefer to use strncat():
(*p)->item[(*p)->sz][0] = '\0'; /* Truncate existing string to empty */
strncat((*p)->item[(*p)->sz], data, (sizeof (*p)->item[(*p)->sz]) - 1);