As a homework, I've written this program that is supposed to sort a console input using qsort_r (this is the one thing I can't change, we're required to use qsort_r). We were supposed to implement three different sorting functions; compVal sorts the inputs normally by value, compOnes orders the inputs by the amount of 1s their bit value contains, and compBitSeq orders them by the longest bit sequence (and the sorting is supposed to work both ways, hence the direction variable).
The normal sorting function works fine. I can't get compOnes and compBitSeq to work, though. I've tried out the auxiliary functions countOnes and bitSequence on their own; they seem to work just fine and do what I expect them to. The program as a whole, however, gives me a segmentation error when I try to tun it.
Since I'm not super secure with pointers yet, I cannot really pinpoint what is wrong here. I do assume that there might be a problem in passing a function to a function and that I'm not passing all the values correctly, but I'm not sure how else to do this? I have tried putting everything in one function, which is very unelegant since I have to do the same loop to find both acount and bcount, but that also didn't work. qsort_r is also cutting down my flexibility here since I have to stick to the data types that the function requires.
I've now got rid of the segmentation fault, interchanging the function strcomp with memcmp did the trick! Now I do get an output, but it's not as desired and I can't get behind what's wrong here. I've tried out my countOnes and bitSeq functions with a couple of values and the output tells me that the values that are being determined are right (I commented that in my code so I know what order it should be in). But the sorting seems to be totally random (well it probably isn't, but I really can't tell what it sorts by... and I do feel like the output is different every time, even with the same numbers, especially if I enter them in a different order), even for the totally normal sorting sequence.
If this helps, I now modified my functions so the print what numbers they are comparing, and... it's some negative numbers:
number a: -41, number b: -39, order: -2
number a: -34, number b: -31, order: -3
number a: -36, number b: -34, order: -2
number a: -41, number b: -36, order: -5
number a: -39, number b: -36, order: -3
3, 15, 7, 97, 32
(obviously, the numbers came out as they went in, since the values all give a negative result...)
Where do they come from? Apparently I passed something wrong but I can't tell what...? Maybe some of the data types got jumbled up, but I can't find out which and where. I tried to change around some things, but that didn't help.
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int compVal (const void *a, const void *b, void *direction) {
int order = memcmp(a, b, sizeof(char)) * *(int *) direction;
printf("number a: %d, number b: %d, order: %d\n", *(char *)a, *(char *)b, order);
if (order > 0) {
return 1;
} else if (order < 0) {
return -1;
} else {
return 0;
}
}
int countOnes (char number) {
int counter = 0;
for (int i = 0; i < (8 * sizeof(char)); i++) {
if (number & 1) {
counter += 1;
}
number = number >> 1;
}
return counter;
}
int bitSequence (char number) {
int bit = number & 1;
number = number >> 1;
int current = 1, max = 1;
for (int i = 1; i < (8 * sizeof(char)); i++) {
if ((number & 1) == bit) {
current += 1;
if (current > max) {
max = current;
}
} else {
current = 1;
}
bit = number & 1;
number = number >> 1;
}
return max;
}
int compOnes (const void *a, const void *b, void *direction) {
char achar = *(char *) a, bchar = *(char *) b;
char acount = countOnes(achar);
char bcount = countOnes(bchar);
//return memcmp(&acount, &bcount, sizeof(char)) * *(int *) direction;
printf("ones a: %d, ones b: %d\n", acount, bcount);
return compVal(&acount, &bcount, &direction);
}
int compBitSeq (const void *a, const void *b, void *direction) {
char achar = *(char *) a, bchar = *(char *) b;
char aseq = bitSequence(achar);
char bseq = bitSequence(bchar);
//return memcmp(&aseq, &bseq, sizeof(char)) * *(int *) direction;
printf("sequence a: %d, sequence b: %d\n", aseq, bseq);
return compVal(&aseq, &bseq, &direction);
}
int main (int argc, char* argv[]) {
if (argc < 3) {
printf("At least 2 values needed for sorting\n");
return EXIT_FAILURE;
}
int direction = 1;
qsort_r(&argv[1], argc - 1, sizeof(char *), compVal, &direction); // 3, 7, 15, 32, 97
//qsort_r(&argv[1], argc - 1, sizeof(char *), compOnes, &direction); // 32, 3, (7, 97), 15
//qsort_r(&argv[1], argc - 1, sizeof(char *), compBitSeq, &direction); // (97, 15), (7, 32), 3
//char test1 = countOnes(3), test2 = countOnes(7), test3 = countOnes(15), test4 = countOnes(32), test5 = countOnes(97);
//printf("%d, %d, %d, %d, %d\n", test1, test2, test3, test4, test5); // 2, 3, 4, 1, 3
//test1 = bitSequence(3), test2 = bitSequence(7), test3 = bitSequence(15), test4 = bitSequence(32), test5 = bitSequence(97);
//printf("%d, %d, %d, %d, %d\n", test1, test2, test3, test4, test5); // 6, 5, 4, 5, 4
for (int i = 1; i < argc; i++) {
if (i == argc -1) {
printf("%s\n", argv[i]);
} else {
printf("%s, ", argv[i]);
}
}
return EXIT_SUCCESS;
}
You are passing a pointer to int to strcmp(), that invokes undefined behavior because strcmp() expects a nul terminated sequence of bytes which an integer is not.
Try with
memcmp(a, b, sizeof(int));
Also sizeof(char) is always 1, whereas CHAR_BIT is not necessarily 8 so this
for (int i = 1; i < 8 * sizeof(char); i++)
can be
for (int i = 1 ; i < CHAR_BIT ; i++)
instead.
Related
I'm trying to compare the bits of variable number of arguments and print their value. but I'm getting garbage. what am I doing wrong?
My Code:
#include <stdio.h>
#include <stdarg.h>
void and_bits(unsigned int num, ...)
{
unsigned int i = 0;
/* result is 11111111 in binary*/
unsigned int result = 255;
va_list arglist;
va_start(arglist, num);
/* this loop takes each argument, and apply AND bitwise operator to the next argument*/
for (i = 0; i < num; i++)
{
/* bitwise AND operator */
result &= va_arg(arglist,unsigned int);
printf("%u, ",va_arg(arglist,unsigned int));
}
va_end(arglist);
printf("\nthe return value: base 10 = %u\t", result);
printf("base 16 = %x\n", result);
return;
}
int main(void)
{
and_bits(7,2,3);
return 0;
}
The Output:
3, 0, 0, 1987831328, 0, 3742925664, 3742924928,
the return value: base 10 = 0 base 16 = 0
So, you have two problems. The first is covered in comments, but essentially you're not calling and_bits correct. The first argument should be a count.
But you have a bigger problem, right here:
for (i = 0; i < num; i++)
{
/* bitwise AND operator */
result &= va_arg(arglist,unsigned int);
printf("%u, ",va_arg(arglist,unsigned int));
}
Every time you call va_arg(), you advance the argument pointer by one. So assuming you've called and_bits(3, 7, 2, 3), then on the first iteration of the loop:
You call va_arg(), which returns the value 7, and you set result to result & 7.
Then on the next line, you call va_arg(), which returns 2, so you print that out.
Then in the next iteration of the loop:
You call va_arg(), which returns 3, and set result to result & 3.
You call va_arg() again, but you've already consumed three arguments so now you're reading beyond the argument list and you get undefined results.
You're going to go through the loop one more time, and at this point all values returned by va_arg() will be invalid.
You should modify the loop so that it only calls va_arg() once:
#include <stdio.h>
#include <stdarg.h>
void and_bits(unsigned int num, ...)
{
unsigned int i = 0;
/* result is 11111111 in binary*/
unsigned int result = 255;
va_list arglist;
va_start(arglist, num);
/* this loop takes each argument, and apply AND bitwise operator to the next argument*/
for (i = 0; i < num; i++)
{
/* bitwise AND operator */
unsigned int val = va_arg(arglist,unsigned int);
result &= val;
printf("%u: val=%u, result=%u\n", i, val, result);
}
va_end(arglist);
printf("\nthe return value: base 10 = %u\t", result);
printf("base 16 = %x\n", result);
return;
}
int main(void)
{
and_bits(3, 7,2,3);
return 0;
}
Which produces as output:
0: val=7, result=7
1: val=2, result=2
2: val=3, result=2
the return value: base 10 = 2 base 16 = 2
I encountered a hard question I don't know the answer to: "Rearrange the digits from an integer in blocks of two with a recursive function" here's an example:
Input: 123456
unsigned long pairinvPrint(unsigned long number) {
printf("%d", number % 100);
if ((number / 100) <= 99) {
printf("%d", number / 100);
}
else {
pairinv(number / 100);
}
}
Output: 563412
More I/O Examples: 42 -> 42; 1234 -> 3412
However, the set circumstances to do this are hard (no loops, arrays, pointers, global- or static variables, no libraries) and it should not print the solution directly, rather return it upon a call like this:
printf("Rearrange int (%lu) = %lu", input, pairinvert(input));
Luckily there's one circumstance to make it easier, the number of the input digits is always even.
Now I experimented for a while, but cant come up with a working solution, except the invalid one using printf.
Does anyone have some inspiration for me or idea how to tackle this?
I'll bite :-)
unsigned long p(unsigned long p1, unsigned long p2) {
// no loops, no arrays, no pointers, no global, no static, no variables, no libraries
if (p1 < 100) return p2*100 + p1;
return p(p1/100, p2*100 + p1%100);
}
unsigned long pairinvert(unsigned long n) {
// no loops, no arrays, no pointers, no global, no static, no variables, no libraries
if (n < 100) return n;
return p(n/100, n%100);
}
// need <stdio.h> for printf()
#include <stdio.h>
int main(void) {
unsigned long input;
input = 123456;
printf("Rearrange int (%lu) = %lu\n", input, pairinvert(input));
input = 42;
printf("Rearrange int (%lu) = %lu\n", input, pairinvert(input));
input = 1234;
printf("Rearrange int (%lu) = %lu\n", input, pairinvert(input));
}
Following program should work.
#include <stdio.h>
void rearrange(int n, int *output) {
int lsd = 0, slsd = 0;
if(n == 0)
return;
if(n > 0) {
lsd = n%10;
}
if (n > 9) {
slsd = (n%100)/10;
}
*output = 100*(*output) + 10*slsd + lsd;
n = n/100;
rearrange(n, output);
}
int main() {
int n;
int output = 0;
scanf("%d", &n);
rearrange(n, &output);
printf("%d\n", output);
return 0;
}
It is simple to understand, so I am not writing any comments.
Note that it is tail recursive so with O2 optimization it can recurse infinitely.
Try this :
unsigned long pairinv(unsigned long number, unsigned long result) {
unsigned long n = number % 100; // Gets the two digit number
if (n == 0) return result; // If it's zero returns the result
result = result * 100 + n; // Else multiplies the result by 100, adds n
return pairinv(number / 100, result); // and continues by recursion
}
int main() {
unsigned long r= 0;
printf("%lu\n", pairinv(123456, r)); //==> 563412
return 0;
}
I need to write a function that replaces 2 "numeric numbers", of otherwise unknown type.
I don't know the exact type and I can only use 2 parameters.
So this is what I have tried:
void swap(void *p1, void *p2)
{
char p;
char * q1 = (char *)p1;
char * q2 = (char *)p2;
for (int i = 0; i < sizeof(long double); i++)
{
p = q1[i];
q1[i] = q2[i];
q2[i] = p;
}
}
Usage:
double a = 100123000000.2;
double b = 100065450000.3;
printf("a: %1f, b: %1f\n", a, b);
swap(&a, &b)
printf("a: %1f, b: %1f\n", a, b);
This works fine but my question is what if my number is bigger then long double (or there is no one..)
Is my solution OK?
This works fine but my question is what if my number is bigger (?)
Is my solution is OK ?
Code will have trouble unless it knows the exact size. So, no, OP's solution is not OK.
Somehow void swap() needs to know the size of the data to swap.
i can only use 2 parameters.
Code can cheat and put all the data into 1 argument as a compound literal, since C99.
typedef struct {
void *a;
void *b;
size_t sz;
} swap_T;
// Only 1 parameter!!
void swap(swap_T sw) {
unsigned char * q1 = sw.a;
unsigned char * q2 = sw.b;
while (sw.sz > 0) {
sw.sz--;
unsigned char p = q1[sw.sz];
q1[sw.sz] = q2[sw.sz];
q2[sw.sz] = p;
}
}
int main(void) {
double a = 100123000000.2;
double b = 100065450000.3;
printf("a: %g, b: %g\n", a, b);
swap(((swap_T ) { &a, &b, sizeof a } )); // Compound literal
printf("a: %g, b: %g\n", a, b);
return 0;
}
Output
a: 1.00123e+11, b: 1.00065e+11
a: 1.00065e+11, b: 1.00123e+11
Code could wrap the swap(((swap_T ) { &a, &b, sizeof a } )) in a macro that looks like a function call of 2
#define SWAP(a,b) (swap(((swap_T ) { &(a), &(b), sizeof (a) } )))
...
SWAP(a,b);
As long as a is not an expression with a variable logic array (VLA) and with side-effects, the macro should work fine.
Of course, best if a,b are the same type.
Your program should try to retrieve sizeof of its argument to know how many bytes to swap - perhaps as a third argument - you have no way of telling otherwise how big an argument is. With current function you will overwrite memory which will end up badly - especially in a bigger program. For example, consider a following program.
#include <stdio.h>
int main() {
int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
swap(&a[0], &a[4]);
for (int i = 0; i < 8; i++) {
printf("%d\n", a[i]);
}
}
Which will return 5, 6, 7, 8, 1, 2, 3, 4 - which clearly isn't expected - only 0th and 4th array elements should have been swapped.
It's possible to hide getting size behind a macro if needed.
#define SWAP(a, b) swap(&(a), &(b), sizeof(a))
I'm trying to build a recursive function which returns the address within a sorted array by comparing to the middle value and proceeding based on relative size. Should the value not be in the array, it is supposed to simply print NULL. Now the first part of the function works, however whenever a null is supposed to happen I get a segmentation fault. The code looks as follows:
#include <stdio.h>
int *BinSearchRec(int arr[], int size, int n){
if(n==arr[size/2]){
return &arr[size/2];
}
else if(n>arr[size/2]) {
return(BinSearchRec(arr, size+size/2, n));
}
else if(n<arr[size/2]) {
return(BinSearchRec(arr, size-size/2, n));
}
else{
return NULL;
}
}
main(){
int numb[]={2,7,8,9};
if((int)(BinSearchRec(numb, 4, 22)-numb)>=0) {
printf("Position: %d \n", (int)(BinSearchRec(numb, 4, 22)-numb)+1);
}
else{
printf("NULL \n");
}
}
Your recursive calls are wrong. In the first case you claim that the size of the array is 50% larger than originally, and you're passing the pointer wrong (you should pass the second "half" of the array).
In both cases, the size of the "array" is always half of what the function received. And in the second case, you need to pass a pointer to the second half of the array.
Something like
else if(n>arr[size/2]) {
return(BinSearchRec(arr + sizeof/2, size/2, n));
}
else if(n<arr[size/2]) {
return(BinSearchRec(arr, size/2, n));
}
You're also treating the returned value from the function wrong. It's not a value, it's a pointer to the value, you need to treat it as such. And it's okay to subtract one pointer from another (related) pointer, it's called pointer arithmetics.
In addition to what others have said about not dividing the array properly and not using the return value correctly, your function is missing a termination condition.
In your code, the las else will never be reached, because the three preceding conditions cover all possibilities: n is either smaller than, equal to or greater than arr[size/2].
You should test whether your subarray actually has elements before you access and compare them. Here's a revision of your code:
int *BinSearchRec(int arr[], int size, int n)
{
int m = size/2;
if (size == 0) return NULL;
if (n > arr[m]) return BinSearchRec(arr + m + 1, size - m - 1, n);
if (n < arr[m]) return BinSearchRec(arr, m, n);
return &arr[m];
}
And here's an example main that shows how you make use of the pointer that was returned. If the pointer is NULL, the number is not in the array and you cannot dereference the pointer.
int main()
{
int numb[] = {2, 7, 8, 9};
int n;
for (n = 0; n < 15; n++) {
int *p = BinSearchRec(numb, 4, n);
if (p) {
printf("%d: #%d\n", n, (int) (p - numb));
} else {
printf("%d: NULL\n", n);
}
}
return 0;
}
Instead of using a single size, it is easier to reason with 2 indexes (left and right) delimiting the sub-array you are exploring.
Modifying your code according to this approach gives:
#include <stdio.h>
#include <stdlib.h>
int *BinSearchRec(int arr[], int left, int right, int n){
if (left > right)
return NULL;
int mid = (left + right) / 2;
if(n == arr[mid])
return &arr[mid];
if(n > arr[mid])
return BinSearchRec(arr, mid + 1, right, n);
else
return BinSearchRec(arr, left, mid - 1, n);
}
int main(int argc, char *argv[]){
int numb[] = {2,7,8,9};
int *p = BinSearchRec(numb, 0, 3, 22);
if (p) {
printf("Position: %d \n", (int) (p - numb + 1));
} else {
printf("NULL \n");
}
return 0;
}
I have been stuck on this for a while and nothing seems to work.
I have a data structure:
DATA
{
int size;
int id;
}
And I have an array of DATA structures:
myArray = (DATA *) malloc(10 * sizeof(DATA));
Then I assign some test values:
myArray[0].size = 5;
myArray[1].size = 9;
myArray[2].size = 1;
myArray[3].size = 3;
So my starting array should look like:
5,9,1,3,0,0,0,0,0,0
Then, I call qsort(myArray,10,sizeof(DATA),comp)
Where comp is:
int comp(const DATA * a, const DATA * b)
{
return a.size - b.size;
}
And trust me, I tried many things with the compare function, NOTHING seems to work. I just never get any sorting that makes any sense.
So my starting array should look like 5, 9, 1, 3, 0, 0, 0, 0, 0, 0.
No, it really won't, at least it's not guaranteed to.
If you want zeros in there, either use calloc() to zero everything out, or put them in yourself. What malloc() will give you is a block of the size required that has indeterminant content. In other words, it may well have whatever rubbish was in memory beforehand.
And, on top of that, a and b are pointers in your comp function, you should be using -> rather than . and it's good form to use the correct prototype with casting.
And a final note: please don't cast the return from malloc in C - you can get into problems if you accidentally forget to include the relevant header file and your integers aren't compatible with your pointers.
The malloc function returns a void * which will quite happily convert implicitly into any other pointer.
Here's a complete program with those fixes:
#include <stdio.h>
#include <stdlib.h>
typedef struct {int size; int id;} DATA;
int comp (const void *a, const void *b) {
return ((DATA *)a)->size - ((DATA *)b)->size;
}
int main (void) {
int i;
DATA *myArray = malloc(10 * sizeof(DATA));
myArray[0].size = 5;
myArray[1].size = 9;
myArray[2].size = 1;
myArray[3].size = 3;
for (i = 4; i < 10; i++)
myArray[i].size = 0;
qsort (myArray, 10, sizeof(DATA), comp);
for (i = 0; i < 10; i++)
printf ("%d ", myArray[i].size);
putchar ('\n');
return 0;
}
The output:
0 0 0 0 0 0 1 3 5 9