I am currently unit testing the generic quicksort I made for which i will post the code right here below, along with the compare method I'm using and the code I'm running to test it.
The problem I find is that the array is not actually being sorted. The assertion fails and if I try to print the array after sorting it just prints the values in the predetermined order.
I tried unit testing the algorithm for int and float values and it did sort just fine.
I believe the problem may lie in the fact that I probably did not cast correctly the void pointer, resulting in undefined behaviour
void quicksort(void* pointer, int size, int start, int end, int (*compare)(void*,void*)){
if(end > start){
int index = partition(pointer, size, start, end,compare);
quicksort(pointer,size,start,index-1,compare);
quicksort(pointer,size,index+1,end,compare);
}
}
int partition(void * pointer, int size, int start, int end, int (*compare)(void*,void*)){
int beginning = start + 1;
int ending = end;
while(beginning <= ending){
if(compare(&pointer[beginning*size],&pointer[start*size]) >= 0){
beginning++;
}
else{
if(compare(&pointer[ending*size],&pointer[start*size]) == -1){
ending--;
}
else{
swap(&pointer[beginning*size],&pointer[ending*size],size);
beginning++;
ending--;
}
}
}
swap(&pointer[start*size],&pointer[ending*size],size);
return ending;
}
void swap(void* datablocka, void* datablockb, size_t elem_size){
char temp;
char *chara = datablocka;
char *charb = datablockb;
while(elem_size--){
temp = chara[elem_size];
chara[elem_size] = charb[elem_size];
charb[elem_size] = temp;
}
}
int compare_string(void* first, void* second){
char * a = first;
char * b = second;
int compare = strcmp(a,b);
if (compare < 0) return 1;
else if(compare == 0) return 0;
else return -1;
}
void quicksort_string_utest() {
char* a[] = {"a","aaa","abba","mime","pippo","cacciatorpediniere"};
char* b[] = {"a","aaa","abba","cacciatorpediniere","mime","pippo"};
int end = (sizeof(a)/sizeof(a[0]))-1;
quicksort(a, sizeof(a[0]), 0, end, compare_string );
for(int i = 0; i < 6; i++){
assert(strcmp(a[i],b[i]) == 0);
}
}
I would really appreciate your help with this, since as you can see I can't sort this out
In this program, what is passed to the comparision function compare_string is pointers to elements of the array.
In this case, elements of the array is char* and what is passed is pointers to char*.
Therefore, to obtain the pointers to strings, you have to dereference the passed pointers.
Try this:
int compare_string(void* first, void* second){
char ** a = first;
char ** b = second;
int compare = strcmp(*a,*b);
if (compare < 0) return 1;
else if(compare == 0) return 0;
else return -1;
}
Related
I have done a code to solve the Sum String as Numbers problem on CodeWars.
On my machine it runs and returns the correct value, it also passes all tests on CodeWars, but for some reasons it's raised the Caught unexpected signal: 6 and free(): invalid pointer.
I have checked other questions related to this and other forums but it seems that i don't anything form there. I have used only size_t my pointer don't increase like a++ or anything in order to free to not be able to dealocate memory.
My code consists on:
a function char *to_num(const char *a,size_t *size) which converts all digits from ASCII to numbers (i.e. '3' => 3) and returns a char* to a dynamic allocated array with all that numbers. Also it removes all prefixed zeros.
void no_zeros(char *a) which simply deletes all the 0 from the start of a string (i.e. "0012" => "12")
a custom len function, because i use a different nul character, as my 0 in array is tehnically 0 digit. On this example i use 10 as terminating character
char *fill(char* a,size_t size) that returns a string prefixed with as many zeros as needed to reach the length size (i.e. for a="12" and size=4 it returns 0012)
and finnaly the main function char *strsum(const char *a, const char *b) which returns the sum written as a string (i.e. "123" + "456" returns "579")
The flow of this program goes like:
convert the strings received as parameter to numbers with to_num
if one number is longer than another the fill function is called to complet the smaller one so that we can perform the addition
than we perform the addition per components and return the number as string
I have a bug that prefixes my result with zero so i call the no_zeros on resut.
My code
#include <stdio.h>
#include <malloc.h>
#include <string.h>
void display(const char *a,size_t size){
for(size_t i=0;a[i]!=0 && i<size;i++){
if(a[i]>'0'){
printf("%c",a[i]);
}
else{
printf("%d",a[i]);
}
}
printf("\n");
}
char *to_num(const char *a,size_t *size){
size_t i=0,j=0;
*size = strlen(a);
char *result = malloc((*size+1)*sizeof(char));
if(result==NULL){return 0;}
while(a[i]=='0'){i++;}
while(a[i]!=0){
result[j] = a[i];
i++;
j++;
}
result[j]=0;
*size = j;
for(size_t i=0;i<*size;i++){
result[i] = result[i]-'0';
}
result[*size] =10;
return result;
}
void no_zeros(char *a){
size_t i=0,j=0;
while(a[i]=='0'){i++;}
while(a[i]!=0){
a[j] = a[i];
i++;
j++;
}
a[j]=0;
}
size_t len(char *a){
size_t s=0;
for(size_t i=0;a[i]!=10;i++){
s++;
}
return s;
}
char *fill(char* a,size_t size){
size_t a_size = len(a);
char *copy = malloc((size+2)*sizeof(char));
if(copy==NULL){return 0;}
for(size_t i=0;i<size-a_size;i++){
copy[i] = 0;
}
for(size_t i=0;i<a_size;i++){
copy[i+size-a_size] = a[i];
}
copy[size] = 0;
for(size_t i=0;i<size;i++){
}
return copy;
}
char *strsum(const char *a, const char *b)
{
size_t size_a,size_b,bigger,smaller;
char *x,*y;
x = to_num(a,&size_a);
y = to_num(b,&size_b);
bigger = size_a>=size_b ? size_a : size_b;
smaller = size_a<=size_b ? size_a : size_b;
if(bigger != smaller){
if(bigger == size_a){
y = fill(y,bigger);
size_b = bigger;
}
else{
x = fill(x,bigger);
size_a = bigger;
}
}
char *result = malloc((bigger+2)*sizeof(char));
if(result==NULL){return 0;}
int carry=0;
size_t i;
for(i=bigger;i>=0;i--){
result[i] = (x[i-1]+y[i-1]+carry)%10+'0';
carry = (x[i-1]+y[i-1]+carry)/10;
if(i==0) break;
}
result[bigger+1]=0;
no_zeros(result);
if(result[0]==0){return "0";}
free(x);
free(y);
return result;
}
int main(){
printf("%s\n",strsum("9567","800"));
}
display(): for(size_t i=0;a[i]!=0 && i<size;i++){: swap the order of the conditions so you do the boundary check before a[i].
strsum(): for(i=bigger;i>=0;i--){ doesn't make sense as i is a size_t i.e. unsigned and in the loop body you do x[i-1] and y[i-1] which is wrong when i is 0. What about this?
for(i=bigger; i; i--){
result[i] = (x[i-1]+y[i-1]+carry)%10+'0';
carry = (x[i-1]+y[i-1]+carry)/10;
}
result[0] = carry + '0';
strsum(): x and y leak as you free them after a return:
free(x);
free(y);
if(result[0]==0){return "0";}
strsum(): to_num() allocates an array and then fill() allocates a copy (2 mallocs) and in strsum() you may leak the first malloc() for either x or y:
x = to_num(a,&size_a);
y = to_num(b,&size_b);
// ...
if(bigger != smaller){
if(bigger == size_a){
y = fill(y,bigger);
size_b = bigger;
}
else{
x = fill(x,bigger);
size_a = bigger;
}
}
Either realloc() in fill() instead of creating a copy or use a temporary variable in strsum() so you can free the original malloc'ed value:
if(bigger != smaller){
if(bigger == size_a){
char *tmp = fill(y, bigger);
free(y);
y = tmp;
size_b = bigger;
}
else{
char *tmp = fill(x, bigger);
free(x);
x = tmp;
size_a = bigger;
}
}
Btw, this is the same code in both branches so consider writing a function.
main(): leaks the returned string:
int main(){
char *s = strsum("9567","800");
printf("%s\n", s);
free(s);
}
strsum(): Once you fix above mention leak in main() you can no longer do return "0". You would need a size check and possible realloc() before doing:
return strcpy(result, "0");
or you could free(result); return strdup("0");. This is most likely the root cause (in calling test code you don't see).
I am trying to solve a problem in which I need to implement a function that receives a void pointer as an argument. This function needs to search an array for a specific value and return a pointer to the value.
The *arr == *val comparison statement produces a "Invalid operands to binary expression ('void' and 'void')" when I run the following code. I have not been able to figure out why.
void* search(void *arr, int n, void* val, char c){
if(c == 'c') {
arr = (char*) arr;
val = (char*) val;
} else if(c == 'i'){
arr = (int*) arr;
val = (int*)val;
} else {
arr = (float*)arr;
val = (float*)val;
}
for (int i = 0; i < n; i++) {
if(*arr == *val){
return arr;
} else {
arr++;
}
return NULL;
}
}
You get the error because it doesn't make sense to de-reference void pointers.
Some compilers like gcc -std=gnu11 have dangerous compiler extensions enabled by default, which hide bugs in the program. The bugs being that you can't de-reference a void pointer nor can you do arithmetic (++) on one. You have to cast the void pointers to some data pointers first.
The statement arr = (char*) arr; says “Take the value of arr, convert that value to a char *, and assign that value to arr.” It does not say “Change the type of arr to be a char *.”
Below are several ways you can write code in C that works with multiple types.
One is to write code for each type you want to support:
void *search(void *arr, int n, void *val, char c)
{
switch (c)
{
case 'c':
{
char *a = arr, *v = val;
for (int i = 0; i < n; ++i, ++a)
if (*a == *v)
return a;
return NULL;
}
case 'i':
{
int *a = arr, *v = val;
for (int i = 0; i < n; ++i, ++a)
if (*a == *v)
return a;
return NULL;
}
default:
{
float *a = arr, *v = val;
for (int i = 0; i < n; ++i, ++a)
if (*a == *v)
return a;
return NULL;
}
}
}
Another is to treat the data as raw bytes:
void *search(void *arr, int n, void *val, char c)
{
// Determine number of bytes in the desired type.
size_t s;
switch (c)
{
case 'c': s = sizeof(char ); break;
case 'i': s = sizeof(int ); break;
default: s = sizeof(float); break;
}
// Set unsigned char pointers to the bytes.
unsigned char *a = arr, *v = val;
/* Compare the s bytes of the current element at a to the bytes of v.
In each iteration, advance the pointer a by s bytes.
*/
for (int i = 0; i < n; ++i, a += s)
if (memcmp(a, v, s) == 0)
return a;
return NULL;
}
One problem with the above method is that some types have multiple representations of equal values. That is, different values in the raw bytes may represent the same value. For example, floating-point formats commonly have a −0 representation and a +0 representation that compare equal when the == operator is used but that will be different when their bytes are compared with the memcmp operation above.
A third method is to have the caller provide the size of the object and a routine to compare them:
void *search(void *arr, int n, void *val, size_t s, int compare(void *, void *))
{
// Set unsigned char pointers to the bytes.
unsigned char *a = arr, *v = val;
/* Compare each array element to the target element using the
caller's routine.
In each iteration, advance the pointer a by s bytes.
*/
for (int i = 0; i < n; ++i, a += s)
if (compare(a, v) == 0)
return a;
return NULL;
}
To use the above routine to compare characters, the caller would call it using search(arr, n, &character, sizeof (char), compareC);, where compareC could be:
int compareC(void *a, void *v)
{
char *x = a, *y = b;
if (*x == *y)
return 0;
if (*x < *y)
return -1;
else
return +1;
}
My homework requires me to write a program that takes a string from the terminal (argc and argv) and print every possible permutation. I have tried to use Heap's Algorithm, but it doesn't seem to be working out. Below is my function.
char **getPermutation(char * in)
{
//n is the size of the input string.
int n = strlen(in);
int count[n];
int counter= 0;
char copy[n];
char **permutations = malloc(sizeof(char*)*(factorial(n)));
permutations[0] = in;
strcpy(in, copy);
counter++;
for( int i = 1; i < n;)
{
if (count[i] < i){
if (i%2==0){
swap(&in[0],&in[i]);
}
else
{
swap(&in[count[i]],&in[i]);
}
permutations[counter] = in;
strcpy(in, copy);
counter++;
count[i]++;
i = 1;
}
else
{
count[i] = 0;
i++;
}
}
return permutations;
}
The function must return the pointer to the character pointer as specified by the instructions. That's also why there are so many variables (although, I'm not really sure what to do with the copy of the string. I'm fairly sure I need it). Testing shows that the program will loop, often too much and eventually hit a seg fault. It doesn't seem like the swapped strings make it into the returned array on top of that.
Below is a rework of your code with cleaned up memory allocation and it addresses some problems mentioned in the above comments. Additionally, you have a bug in your algorithm, this statement strcpy(in, copy); keeps you from getting all the permutations (causes repeats instead.) This code works but isn't finished, it can use more error checking and other finishing touches:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
unsigned int factorial(unsigned int n)
{
/* ... */
}
void swap(char *a, char *b)
{
/* ... */
}
char **getPermutations(const char *input)
{
char *string = strdup(input);
size_t length = strlen(string);
char **permutations = calloc(factorial(length), sizeof(char *));
int *counts = calloc(length, sizeof(int)); // point to array of ints all initialized to 0
int counter = 0;
permutations[counter++] = strdup(string);
for (size_t i = 1; i < length;)
{
if (counts[i] < i)
{
if (i % 2 == 0)
{
swap(&string[0], &string[i]);
}
else
{
swap(&string[counts[i]], &string[i]);
}
permutations[counter++] = strdup(string);
counts[i]++;
i = 1;
}
else
{
counts[i++] = 0;
}
}
free(counts);
free(string);
return permutations;
}
int main(int argc, char *argv[])
{
char *string = argv[1];
char **permutations = getPermutations(string);
unsigned int total = factorial(strlen(string));
for (unsigned int i = 0; i < total; i++)
{
printf("%s\n", permutations[i]);
}
free(permutations);
return 0;
}
OUTPUT
> ./a.out abc
abc
bac
cab
acb
bca
cba
>
I tried writing my own insertion sort and swap functions in C.
The insertion sort or the swap is compiling but not working yet.
input: gcc insertion.c -o insertion ./insertion alfalfa
Input: alfalfa
Output: alfalfa
#include <stdio.h>
#include <string.h>
#define SORTL 20
char * insertionsort(int *countargs, char *word);
void swap(char *a, char *b);
/* Enter word to insertion sort at the terminal */
int main(int argc, char *argv[]){
/* Pass arguments from command line */
if(argc != 2)
perror("Please enter two arguments.");
int argcount = strlen(argv[1]);
char presort[SORTL];
strcpy(presort, argv[1]);
char * resultword;
resultword = insertionsort( &argcount, presort );
printf("Presort: %s\nPostsort: %s", presort, resultword);
return 0;
}
char * insertionsort(int *countargs, char word[]){
int i, j;
for( i = 1; i < *countargs; i++) {
j = i;
while( (j < 0) && (word[j] < word[j-1]) ) {
swap( &word[j], &word[j-1] );
j = j - 1;
}
}
return word;
}
void swap(char *a, char * b)
{
char temp;
temp = b;
b = a;
a = temp;
}
You need to change the swap function
void swap(char *a, char * b)
{
char temp;
temp = *b;
*b = *a;
*a = temp;
}
Since, in swap() you need to swap the characters in the memory, and not the address to which the variables are pointing at.
Another thing, by the printf() statement in the end i feel you want to print the older unsorted and the newer sorted string. If so, then it will not work. Only one string will be printed, since essentially you are swapping the characters in the initial string only and resultword is pointing at the same string,
resultword = insertionsort( &argcount, presort );
//sending presort and receiving it in word in the function insertionsort
//receiving the return in resultword
&
return word;
//and returning back the same address from insertionsort
EDIT
The condition in your while loop is incorrect. It should be j > 0
while( (j > 0) && (word[j] < word[j-1]) )
Since you are starting from the far end and going to the beginning.
1. In this function -
void swap(char *a, char * b)
{
char temp;
temp = b; //assigining char * to char
b = a;
a = temp; // same here
}
a and b are char * , dereference pointer a and b and then swap -
void swap(char *a, char * b)
{
char temp;
temp = *b;
*b = *a;
*a = temp;
}
2. In your function -
for( i = 1; i < *countargs; i++) {
j = i;
while( (j < 0) && (word[j] < word[j-1])){ //this loop will not works as j is not < 0
swap( &word[j], &word[j-1] );
j = j - 1;
}
}
Your while loop will not iterate as from starting j is not less than 0 , so second condition is not checked . Inside while loop this condition j<0 should be j>0 .
Can someone please help me with this function.
char *repeat(char *s, int x)
Returns a new string consisting of the characters in s repeated x times. For example, if s is the string all right , the function returns the new string all right all right all right. If s is NULL, the function returns NULL.
It is up to the caller to free any memory allocated by the function.
This is what I have so far...
char *repeat(char *s, int x){
int i;
int count = 0;
while(s[count] != '\0')
{
count++;
}
int repeat = count * x;
char *newArray = malloc(5000);
for(i = 0; i < repeat; i++)
{
while(*s != '\0')
*newArray++ = *s++;
}
return (char*)newArray;
}
char *repeat(const char *s, int x){
if(s){
int i, count = 0;
while(s[count] != '\0'){
++count;
}
char *newArray = malloc(count * x + 1);
if(newArray){
char *na = newArray;
for(i = 0; i < x; ++i) {
const char *p=s;
while(*p)
*na++ = *p++;
}
*na = '\0';
}
return newArray;
} else {
return NULL;
}
}
The main issue--assuming you're only getting one copy back--is that you need to "reset" the pointer s between your copies. Right now, you hit the end of s, so the successive iterations are trying to copy a string of "\0".
Two potential other problems (for the future) are:
You should be using (I'm guessing you know this one and aren't allowed to do otherwise) strcpy() to do the copying.
Memory should always be allocated by the function's caller. The pointer to the new string goes on the call stack and the memory goes on the heap technically assigned to repeat(), so when you return, the run-time is under no obligation to preserve any of it for the caller to use. It "usually works," but it can be painfully dangerous.
First allocate memory then copy/move the memory.
For your reference, a simple one(not fully test):
char *repeat(char *s, int x)
{
char *result = malloc(sizeof(s) * x + 1);
while (x > 0) {
strcat(result, s);
x --;
}
return result;
}
int main(int argc, const char * argv[])
{
// insert code here...
char *sample = "hell";
char *result = repeat(sample, 3);
printf("result : %s\n", result);
free(result);
return 0;
}
You'd better:
don't forget x should be the integer and greater than 0;
always remember to free the created string