Here is the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int my_compare(const void * a, const void * b);
int main()
{
char s[][80] =
{ "gxydyv", "gdyvjv", "lfdtvr", "ayfdbk", "sqkpge", "axkoev", "wdjitd", "pyrefu", "mdafyu",
"zdgjjf", "awhlff", "dqupga", "qoprcn", "axjyfb", "hfrgjf", "dvhhhr" };
int i;
puts("#Before:#");
for (i = 0; i < 16; i++)
puts(s[i]);
qsort(s, 16, sizeof *s, my_compare);
putchar('\n');
puts("#After:#");
for (i = 0; i < 16; i++)
puts(s[i]);
return 0;
}
int my_compare(const void *a, const void *b)
{
return strcmp(*(char **)a, *(char **)b);
}
Here is the output:
#Before:#
gxydyv
gdyvjv
lfdtvr
ayfdbk
sqkpge
axkoev
wdjitd
pyrefu
mdafyu
zdgjjf
awhlff
dqupga
qoprcn
axjyfb
hfrgjf
dvhhhr
Segmentation fault
I also notice that the prototype of strcmp is:
int strcmp(const char *s1,const char *s2);
I suppose that the type of a and b in my_compare is "pointer to array-of-char". As a result, *(char **)a is a "pointer to char", which is exactly what strcmp expects.
So where is the problem?
Change:
return strcmp(*(char **) a, *(char **) b);
To:
return strcmp(a,b);
You had an extra level of pointer dereferencing that was incorrect and that's why you got the segfault. That is, you were passing the char values and not the char pointers [which got masked with the cast].
Note: no need to cast from void * here.
UPDATE:
In reponse to your question, yes, because of the way you defined s and the qsort call.
Your original my_compare would have been fine if you had done:
char *s[] = { ... };
And changed your qsort call to:
qsort(s, 16, sizeof(char *), my_compare);
To summarize, here are two ways to do it
int
main()
{
char s[][80] = { ... }
qsort(s, 16, 80, my_compare);
return 0;
}
int
my_compare(const void *a, const void *b)
{
return strcmp(a,b);
}
This is a bit cleaner [uses less space in array]:
int
main()
{
char *s[] = { ... }
qsort(s, 16, sizeof(char *), my_compare);
return 0;
}
int
my_compare(const void *a, const void *b)
{
return strcmp(*(char **) a,*(char **) b);
}
UPDATE #2:
To answer your second question: No
None of these even compile:
return strcmp((char ()[80])a,(char ()[80])b);
return strcmp(*(char ()[80])a,*(char ()[80])b);
return strcmp((char [][80])a,(char [][80])b);
return strcmp(*(char [][80])a,*(char [][80])b);
But, even if the did, they would be logically incorrect. The following does not compile either, but is logically closer to what qsort is passing:
return strcmp((char [80])a,(char [80])b);
But, when a function passes something defined as char x[80] it's just the same as char *x, so qsort is passing char * [disguised as void *].
A side note: Using char *s[] is far superior. It allows for arbitrary length strings. The other form char s[][80] will actually fail if a given string exceeds [or is exactly] 80 chars.
I think it's important for you to understand:
Arrays are call by reference.
The interchangeability of arrays and pointers.
The following two are equivalent:
char *
strary(char p[])
{
for (; *p != 0; ++p);
return p;
}
char *
strptr(char *p)
{
for (; *p != 0; ++p);
return p;
}
Consider the following [outer] definitions:
char x[] = { ... };
char *x = ...;
Either of these two may be passed to strary and/or strptr in any of the following forms [total of 20]:
strXXX(x);
strXXX(x + 0);
strXXX(&x[0]);
strXXX(x + 1);
strXXX(&x[1]);
Also, see my recent answer here: Issue implementing dynamic array of structures
You can just cast it to a const char *, it should work now:
int my_compare(const void *a, const void *b) {
return strcmp((const char *)a, (const char *)b);
}
And also you should add:
#include <stdlib.h>
Related
I'm trying to build a function that checks whether a particular pointer value is stored in a given array. I'm trying to make the function type-agnostic and so I decided to go with the approach that was used to implement qsort(), in which a function pointer is passed to do the type-specific tasks.
The function looks like the following:
int is_in(void* array, int size, void* pelement, int (*equals)(void* this, void* that)) {
for(int k = 0; k < size; k++) {
if(equals(array + k, pelement)) {
return 1;
}
}
return 0;
}
The equals() function checks whether the second parameter is equal to the value pointed at by the first parameter.
One particular implementation of the equals() function that I needed to realize pertains to a struct Symbol type that I created. The implementation looks like the following:
int ptreq(void* ptr1, void* ptr2) {
return ((*((Symbol**) ptr1) == (Symbol*) ptr2));
}
The struct Symbol is defined as follows:
enum SymbolType {
TERMINAL,
NONTERMINAL
} typedef SymbolType;
struct Symbol {
char* content;
SymbolType type;
} typedef Symbol;
void set_symbol(Symbol* pS, SymbolType type, char* content) {
pS->content = malloc(sizeof(content));
strcpy(pS->content, content);
pS->type = type;
}
However, when I tried testing is_in() with a base example, I ended up with incorrect results. For instance, the following code:
#include <stdlib.h>
#include <stdio.h>
#include "string.h"
#include <stdarg.h>
#include <unistd.h>
int main(int argc, char* argv[]) {
Symbol F, E;
set_symbol(&E, NONTERMINAL, "E");
set_symbol(&F, NONTERMINAL, "F");
Symbol** pptest = malloc(2*sizeof(Symbol*));
pptest[0] = &E;
pptest[2] = &F;
printf("Is F in pptest? %d\n", is_in(pptest, 2, &F, &ptreq));
return 0;
}
Gives the following Output:
Is F in pptest? 0
Even though &F is within pptest.
What could be the problem with this approach?
Type void is an incomplete type. So used by you the expression array + k with the pointer arithmetic in the if statement
if(equals(array + k, pelement)) {
is invalid.
Also you need to pass to the function the size of objects stored in the array that will be used in expressions with the pointer arithmetic.
Using your approach the function should be declared similarly to standard C function bsearch that looks like
void *bsearch(const void *key, const void *base,
size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
Only the return type must be changed from void * to int.
That is the declaration pf your function will look like
int is_in( const void *pvalue,
const void *array,
size_t nmemb,
size_t size,
int cmp( const void *, const void *) );
The function can be defined the following way
int is_in( const void *pvalue,
const void *array,
size_t nmemb,
size_t size,
int cmp( const void *, const void *) )
{
size_t i = 0;
while ( i < nmemb && cmp( pvalue, ( const char * )array + i * size ) != 0 ) i++;
return i != nmemb;
}
In general the comparison function shall return an integer less than, equal to, or greater than zero if the searched element is considered, respectively, to be less than, to match, or to be greater than the array element.
In your case as you have an array of pointers that can point to arbitrary objects then the function should return 0 if elements passed to the function are equal each other or just a positive value if they are unequal each other.
int ptreq( const void *ptr1, const void *ptr2 )
{
return *( const Symbol ** )ptr1 != *( const Symbol ** )ptr2;
}
Pay attention to that the passed searched elementmust have the typeSymbol **`.
Here is a demonstration program.
#include <stdio.h>
int is_in( const void *pvalue,
const void *array,
size_t nmemb,
size_t size,
int cmp( const void *, const void * ) )
{
size_t i = 0;
while (i < nmemb && cmp( pvalue, ( const char * )array + i * size ) != 0) i++;
return i != nmemb;
}
int cmp_ptr( const void *ptr1, const void *ptr2 )
{
return *( const int ** )ptr1 != *( const int ** )ptr2;
}
int main( void )
{
int x, y, z;
int * a[] = { &x, &y, &z };
const size_t N = sizeof( a ) / sizeof( *a );
int *pvalue = &y;
printf( "&y is in the array = %s\n",
is_in( &pvalue, a, N, sizeof( *a ), cmp_ptr ) ? "true" : "false" );
int v;
pvalue = &v;
printf( "&v is in the array = %s\n",
is_in( &pvalue, a, N, sizeof( *a ), cmp_ptr ) ? "true" : "false" );
}
The program output is
&y is in the array = true
&v is in the array = false
A Symbol** passed to a void* parameter doesn't come out as an array in the other end unless you cast it to a proper type. array + k is invalid C and will not compile cleanly on conforming compilers. You cannot do pointer arithmetic on void* nor can you iterate through what it points at without knowing the item size - there's a reason why qsort takes that as parameter.
A correctly written standard C function might look something like this:
#include <stddef.h>
#include <stdbool.h>
bool is_in (const void* array,
size_t n_items,
size_t item_size,
const void* element,
int (*equals)(const void*, const void*))
{
unsigned char* byte = array;
for(size_t i=0; i<n_items; i++)
{
if(equals(&byte[i*item_size], element))
{
return true;
}
}
return false;
}
int symbol_equal (const void* obj1, const void* obj2)
{
const Symbol* s1 = obj1;
const Symbol* s2 = obj2;
...
// in case you passed an array of pointers, then an extra level of dereferencing here
}
As others have pointed out, the problem results from trying to perform addition on void*, which is not defined in standard C. While other answers avoid this by passing the item size, as is the case with qsort(), I managed to solve the problem by separating array and k into distinct parameters of the equals() routine, which then performs pointer arithmetic after casting into the proper, non-void* type.
int is_in(void* list, int size, void* pelement, int (*equals)(void* this, int k, void* that)) {
for(int k = 0; k < size; k++) {
if(equals(list, k, pelement)) {
return 1;
}
}
return 0;
}
int ptreq(void* ptr1, int k, void* ptr2) {
return (*(((Symbol**) ptr1) + k) == (Symbol*) ptr2);
}
I have a struct vector that holds it's data in a double void pointer. The struct looks like this:
typedef struct vector {
void **data;
int capacity;
int size;
} vector;
I am trying to somewhat replicate the std::find function in C++ to find items in the vector that I have. I have done this by creating a function vector_find:
int vector_find(vector* v, void *elem, __compar_fn_t cmp)
{
for (int i = 0; i < v->size - 1; i++)
{
if(cmp(v->data[i], elem) == 0)
{
return i;
}
}
return -1;
}
This function is found in my vector.c file. It accepts a comparator function. If it finds the element, it will return its location in the vector.
This is all defined in my vector.c file.
Now I am trying to use this function in one of my programs, in this function:
int cstring_cmp(const void *a, const void *b)
{
const char *ia = *(const char **)a;
const char *ib = *(const char **)b;
printf("%s %s", ia, ib);
return strcmp(ia, ib);
}
void
execute(vector* tokens)
{
if (vector_find(tokens, ";", cstring_cmp) > -1)
{
printf("semicolon found");
}
}
However, when I run this function, I get a segfault with the following error:
Program received signal SIGSEGV, Segmentation fault.
__strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:120
120 ../sysdeps/x86_64/multiarch/../strlen.S: No such file or directory.
A couple of things I have verified:
I have verified that the error occurs in my execute function. Specifically when I call vector_find.
I have verified that this error comes up whether or not tokens is empty. This is interesting because the for-loop in vector_find should never execute if the vector I pass to vector_find is empty.
I have included in both vector.c and the file I am running.
I have also tried this format:
int vector_find(vector* v, void *elem, int (*cmp) (const void*, const void*))
{
for (int i = 0; i < v->size; i++)
{
if((*cmp) (v->data[i], elem) == 0)
{
return i;
}
}
return -1;
}
...and got the same error.
Am I doing this right? Obviously not - where does my error lie?
Your comparison function is expecting that each of its parameters is a char **. However, you call vector_find with a char * being passed as the second parameter which is subsequently passed to cmp. Attempting to use a char * as a char ** invokes undefined behavior as you end up passing to strcmp is actually a char.
You don't show how you populate your vector, but I'm guessing the elements of data are of type char *. That being the case, the comparison function should be expecting a char * instead of a char **.
int cstring_cmp(const void *a, const void *b)
{
const char *ia = a;
const char *ib = b;
printf("%s %s", ia, ib);
return strcmp(ia, ib);
}
If I'm reading this right, you've written a comparator that pretends a vector is a const char*. It isn't. The subsequent C-string comparison is likely not to hit a would-be null terminator and is going to go out of bounds.
Instead, write a comparator that actually compares vector objects to whatever it is that you want to compare them to.
I tried to create some basic code using qsort to sort an array of strings, but it crashes in qsort, according to gdb:
#include <string.h>
#include <stdlib.h>
static int pcmp(const void * a, const void * b)
{
return strcmp(* (char * const *) a, * (char * const *) b);
}
int main()
{
char pn[10][256];
memset(pn, 0, sizeof(char) * 10 * 256);
strcpy(pn[0], "hello");
strcpy(pn[1], "TEST");
strcpy(pn[2], "abc");
strcpy(pn[3], "000000");
qsort(pn, 4, sizeof (char *), pcmp);
}
qsort(pn, 4, sizeof (char *), pcmp);
You tell qsort that what you want to sort is an array of 4 char*, but
char pn[10][256];
actually, pn is an array of 10 char[256]. These things are layout-incompatible, and qsort interprets some bytes in the first of the char[256] as char*s. That's undefined behaviour, and not unlikely to cause a segmentation fault.
To fix it for this special case, you can change your comparison to
static int pcmp(const void * a, const void * b)
{
return strcmp((const char *) a, (const char *) b);
}
and the invocation to
qsort(pn, 4, sizeof pn[0], pcmp);
static int pcmp(const void * a, const void * b)
{
return strcmp( (const char *) a, (const char *) b);
}
int main()
{
char pn[10][256];
strcpy(pn[0], "hello");
strcpy(pn[1], "TEST");
strcpy(pn[2], "abc");
strcpy(pn[3], "000000");
qsort(pn, 4, sizeof (char [256]), pcmp);
return 0;
}
Hello everyone i am writing a program for sorting general element in C. it can sort any type of object(int,float,complex number, objects)
What i have thought of is using void pointers,
void qsort(void *ptr,int sz,int i,int j,int (*fptr) (const void *,const void *) )
{
if(i<j)
{
int p=(i+j)/2;
p=partition(ptr,sz,i,j,p,fptr);
qsort(ptr,size,i,p-1,fptr);
qsort(ptr,size,p+1,j,fptr);
}
}
FOR Comparison
By the value of sz we will know that whether its a pointer to string,int,char,float,etc
int compare(const void* a,const void* b,int sz)
{
if(sz==0) //means pointer to a string
return strcmp( (char*)a, (char*)b );
else if(sz==1) //means int
return *(int*)a - *(int*)b;
else if(sz==2) //means float
return *(float*)a- *(float*)b;
else if(sz==3)
return *(char*)a- *(char*)b;
}
FOR SWAPPING TWO ELEMENTS
void swap(void *a,void *b,int sz)//for swapping
{
if(sz==0)
{
void *c;
c=a;
a=b;
b=c;
}
else if(sz==1)
{
a=(int*)a;
b=(int*)b;
int c;
c= *a;
*a=*b;
*b=c;
}
else if(sz==2)
{
a=(float*)a;
b=(float*)b;
float c;
c= *a;
*a=*b;
*b=c;
}
EDITED
qsort(arr,4,0,9,&compare);
The full code is under construction, please tell me if there could be some optimizations in my approach, or some better alternatives for this problem.
As it seems to me that it is really going to be big in size
Many many thanx in advance
Since your swap routine will likely be used by the partition function, it should work with arbitrary sized objects, not just the ones you plan to pass in to the code.
void swap (void *a, void *b, int sz) {
char buf[512];
void *p = buf;
if (sz > sizeof(buf)) p = malloc(sz);
memcpy(p, a, sz);
memcpy(a, b, sz);
memcpy(b, p, sz);
if (p != buf) free(p);
}
From the way you have written your comparison routine, it seems you only plan to send in certain types of arrays. But, sz is usually used to tell how big the individual elements in the array are, not as a type identifier, as you seem to be trying to use it.
struct x { int key; /*...*/ };
int cmp_x (const void *a, const void *b) {
const struct x *xa = a;
const struct x *xb = b;
return (xa->key > xb->key) - (xa->key < xb->key);
}
struct x array_x[100];
/* populate array */
qsort(array_x, sizeof(struct x), 0, 100, cmp_x);
This is how I imagine your qsort should be called. (Thanks to Ambroz Bizjak for the nifty comparison implementation.)
For an array of int:
int cmp_int (const void *a, const void *b) {
int ia = *(const int *)a;
int ib = *(const int *)b;
return (ia > ib) - (ia < ib);
}
int array_i[100];
/* populate array */
qsort(array_i, sizeof(int), 0, 100, cmp_int);
The problem is that this does not allow sorting of custom types, like structs. The usual approach is to accept a function pointer which you call to do the comparisons.
What you should be doing is passing in the comparison as a function pointer. You are passing in a function pointer but you don't seem to be using it to compare the values. You don't have to predefine all of the comparisons because you can define them when you use them, for the type of values you're using.
Working on using qsort.
#include <string.h>
#include <stdlib.h>
#pragma once
int cstring_cmp(const void *a, const void *b);
int main()
{
int count = 0;
char * randomStr = "sdjsn9i3ms;sa;'smsn92;w;''[w0p4;dsmsdf";
char * charArray[] =
{"s","d","j","s","n","9","i","3","m","s",";","s","a",";","'","s","m","s","n"
,"9","2",";","w",";","'","'","[","w","0","p","4",";","d","s","m","s","d","f"};
size_t strings_len = sizeof(charArray) / sizeof(char *);
/*void qsort(void *base, size_t nel,
size_t width, int (*compar)(const void *, const void *));*/
qsort(charArray, strings_len, sizeof(char *), cstring_cmp);
qsort(randomStr, strings_len, sizeof(char *), cstring_cmp);
// Pause at command prompt
system("pause");
return 0;
} // Close function Main
int cstring_cmp(const void *a, const void *b)
{
const char **ia = (const char **)a;
const char **ib = (const char **)b;
return strcmp(*ia, *ib);
}
So obviously my second qsort is not working. whether that's based on my cstring_cmp function that goes into my qsort not being able to support the base i give it or because my base is not formatted to correctly input into the qsort is a mystery to me.
My Question is how do I convert char * randomStr to char * charArray[] dynamically, during runtime, on the fly, or whatever cool phrase you can come up with. I've searched around a lot and maybe I was just not asking the right question, so I'm coming to you guys for some real question answering power.
Just starting C so if you please try not to fry my brain with your answers me and my brain would appreciate it.
My end goal here is to convert randomStr to a format of charArray, qsort it then convert it back to the randomStr format so i can do some find and replace things I have set up already.
Any help would be great, thanks.
First of all if you use char *randomStr = "Stuff" you can't change it, it's undefined behavior. Second, try this:
int
cmp_fry_brain(const void *a, const void *b)
{
return *((const char *)a) - *((const char *)b);
}
/* This is equivalent to the one above (the compiler will likely emit the
* exact same code).
*/
int
cmp(const void *a, const void *b)
{
const char *x = a;
const char *y = b;
return *x - *y;
}
int
main()
{
char str[] = "This is the end";
qsort(str, strlen(str), 1, cmp_fry_brain);
/* ... */
}