LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 06-18-2023, 08:54 AM   #1
ajiten
Member
 
Registered: Jun 2023
Posts: 375

Rep: Reputation: 4
Unable to get proper output, using void pointer to store and read dynamically allocated array.


Code:
#include <stdio.h>
#include <stdlib.h>
int main(){
    void *arr;
    int n;
    int sum = 0;
    scanf("%d", &n);
    arr = malloc(n*sizeof(int)); //malloc returns a void pointer to the array's starting index, to arr.
    for(int i = 0; i < n; i++){
        scanf("%d", ((int *)arr)[i]);
    }
    for(int i = 0; i < n; i++){
        sum += ((int *)arr)[i];
    }
    printf("%d", sum);
}
The compiled executable does not run properly, as reads the size and then only two inputs, for a given input array size of 5; and then terminates.

Last edited by ajiten; 06-18-2023 at 08:58 AM.
 
Old 06-18-2023, 09:52 AM   #2
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,863

Rep: Reputation: 7311Reputation: 7311Reputation: 7311Reputation: 7311Reputation: 7311Reputation: 7311Reputation: 7311Reputation: 7311Reputation: 7311Reputation: 7311Reputation: 7311
it was told, you need to check compiler warnings too:
Code:
$gcc -o a -Wall a.c
a.c: In function ‘main’:
a.c:10:17: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘int’ [-Wformat=]
   10 |         scanf("%d", ((int *)arr)[i]);
      |                ~^   ~~~~~~~~~~~~~~~
      |                 |               |
      |                 int *           int
Code:
scanf("%d", ((int *)arr+i);
works for me
 
Old 06-18-2023, 10:26 AM   #3
ajiten
Member
 
Registered: Jun 2023
Posts: 375

Original Poster
Rep: Reputation: 4
Quote:
Originally Posted by pan64 View Post
it was told, you need to check compiler warnings too:
Code:
$gcc -o a -Wall a.c
a.c: In function ‘main’:
a.c:10:17: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘int’ [-Wformat=]
   10 |         scanf("%d", ((int *)arr)[i]);
      |                ~^   ~~~~~~~~~~~~~~~
      |                 |               |
      |                 int *           int
Code:
scanf("%d", ((int *)arr+i);
works for me
Thanks, request vetting of the reason why "scanf("%d", ((int *)arr+i));" works, when "scanf("%d", ((int *)arr)[i]);" fails.

The meaning of: ((int *)arr)[i], is still unclear, as it also compiles. Also, the compilation error is for the expression: (int *)arr[i].

Though, ((int *)arr+i)" means what is intended, i.e. the void pointer 'arr' is typecast to int. Then, to the start location, add the value of 'i', to get the correct position.
Next, the contents are read by the scanf() with the %d specifier.

Last edited by ajiten; 06-18-2023 at 10:32 AM.
 
Old 06-18-2023, 01:03 PM   #4
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,782

Rep: Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083
Quote:
Originally Posted by ajiten View Post
[CODE]
void *arr;
[...]
arr = malloc(n*sizeof(int)); //malloc returns a void pointer to the array's starting index, to arr.
[code]
void* converts into any other pointer; since you intent to treat arr as an integer array, it makes more to define it like that directly:

Code:
    int *arr;
    [...]
    arr = malloc(n*sizeof(int));
    [...]
        scanf("%d", arr+i);
        scanf("%d", &arr[i]); /* means the same thing */
 
2 members found this post helpful.
Old 06-18-2023, 01:27 PM   #5
GazL
LQ Veteran
 
Registered: May 2008
Posts: 6,897

Rep: Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019
Quote:
Originally Posted by ajiten View Post
Thanks, request vetting of the reason why "scanf("%d", ((int *)arr+i));" works, when "scanf("%d", ((int *)arr)[i]);" fails.

The meaning of: ((int *)arr)[i], is still unclear, as it also compiles. Also, the compilation error is for the expression: (int *)arr[i].
scanf expects a pointer. array + i evaluates to a pointer, while array[i] evaluates to the value of the base type being pointed to. i.e. there's an implicit dereference operation.

((int *)arr)[i] - cast arr to an int pointer type.
((int *)arr)[i] - apply subscript and evaluate to the value stored at that memory location.

parenthesis are needed because of operator precedence [] is higher than (cast). To get the address you need the address-of operator & e.g.
&((int *)arr)[i]

[] has higher precedence than & so no additional parenthesis are required.

But, honestly this is ugly and you can do it much cleaner:
Code:
#include <stdio.h>
#include <stdlib.h>
int main(){
    void *mem;
    int n;
    int sum = 0;
    scanf("%d", &n);
    mem = malloc(n*sizeof(int)); //malloc returns a void pointer to the array's starting index, to arr.

    for ( int *p = (int *)mem, *end = p + n ; p < end; p++ )
        scanf("%d", p);

    for ( int *p = (int *)mem, *end = p + n ; p < end; p++ )
        sum += *p;

    free(mem);

    printf("%d", sum);
}
That said, unless you're planning to reuse the malloc'd memory for different purposes in your program, probably best just to use the right pointer type to start with as ntubski has pointed out.

P.S. I didn't bother adding them on the above example, but don't forget to check the returns on malloc() and scanf() to catch error conditions.

Last edited by GazL; 06-18-2023 at 01:49 PM.
 
3 members found this post helpful.
Old 06-18-2023, 08:28 PM   #6
ajiten
Member
 
Registered: Jun 2023
Posts: 375

Original Poster
Rep: Reputation: 4
Quote:
Originally Posted by GazL View Post
...
That said, unless you're planning to reuse the malloc'd memory for different purposes in your program, probably best just to use the right pointer type to start with as ntubski has pointed out.

P.S. I didn't bother adding them on the above example, but don't forget to check the returns on malloc() and scanf() to catch error conditions.
Please tell if your postscript refers to the compilation option, that treats warnings as error, i.e.: -W -Wall -werror?

---------------

Also, my attempt on void pointer being used for passing array as a parameter, are based on finding a complete code to the program for Quicksort code, given incomplete in the book: Algorithms in a nutshell, by George T. Heineman.
The book states the below parts, leaving out the main(), cmp(), selectPivotIndex functions' implementation to the user.

Code:
void sortPointers(void **vals, int total_elems, int(*cmp)(const void *, const void *))
{
    do_qsort(vals, cmp, 0, total_elems-1);
}

void do_qsort(void **ar, int(*cmp)(const void *, const void *), int left, int right)
//left is for the start/left index position in the array/sub-array. Similarly, for the right variable.
{
   int pivotIndex;
   if(right<=left) return;
   
   //partition
   pivotIndex = selectPivotIndex(ar, left, right);
   pivotIndex = partition(ar, cmp, left, right, pivotIndex);

   if(pivotIndex - 1 - left<= minSize) //to have a lesser time complexity method, for lesser size of the input array/sub-array.
       insertion(ar, cmp, left, pivotIndex-1);
   else
       do_qsort(ar, cmp, left, pivotIndex-1);
   if (right - pivotIndex -1 <= minSize)
       insertion(ar, cmp, pivotIndex+1, right);
   else do_qsort(ar, cmp, pivotIndex+1, right);
}

/*partition ar{left, right] around a given pivot element, ar[pivotIndex], in linear time; by storing pivot into its pivot location.
The location of pivot, is given in store , s.t. all ar[left, store) <= pivot, and all ar[store+1, right] > pivot. */
int partition(void **ar, int(* cmp)(const void *, const void *), int left, int right, int pivotIndex)
{
   int idx, store;
   void *pivot = ar[pivotIndex];

   /*move pivot to the end of the array*/
   void *tmp = ar[right];
   ar[right] = ar[pivotIndex];
   ar[pivotIndex] = tmp;

   //all values sorted in two sub-arrays, i.e. <= pivot, and > pivot. The values <= pivot are moved to front of the (sub)array, & pivot inserted just after them.
   store = left;
   for(idx = left; idx < right; idx++)
   {
      if(cmp(ar[idx], pivot) <= 0)
      { 
          tmp = ar[idx]; ar[idx] = ar[store];  ar[store] = tmp;  store++;
      }
   }

   tmp = ar[right]; ar[right] = ar[store]; ar[store] = tmp;
   return store;
}
To make the program work, need to devise the main() (calling the sortPointers), cmp(), and the selectPivotIndex() functions.

1. main() should call the function sortPointers function, and my estimate is:
int main()
{
void *vals;
int total_elements;
//have used dynamically created array, but a static array would also be fine.
printf("Enter the number of array elements"); scanf("%d", &total_elements);
vals = malloc(total_elements*sizeof(int));
for (int *p = (int *)mem, *end = p + total_elements; p < end; p++)
scanf("%d", p);
//finally, using static or dynamic array, the contents are: {15, 9, 8, 1, 4, 11, 7, 12, 13, 6, 5, 3, 16, 2, 10, 14}
return sort_Pointers(vals, total_elements,

//But, need to build the cmp function, that am confused about.

[/CODE]

Kindly tell if need to frame a new question, or is it fine, to ask about the construction of the cmp function, here?

Assuming yes, would like to add that am not using, the first parameter of the main(), as a void **, but a void *, i.e. single level of indirection is being used.

So, feel that the input parameter to the function sortPointers, is to be modified; but not clear.

Last edited by ajiten; 06-19-2023 at 03:19 AM.
 
Old 06-18-2023, 10:27 PM   #7
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=15, FreeBSD_12{.0|.1}
Posts: 6,267
Blog Entries: 24

Rep: Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195Reputation: 4195
Quick partial answers, others feel free to elaborate...

Quote:
Originally Posted by ajiten View Post
Please tell if your postscript refers to the compilation option, that treats warnings as error, i.e.: -W -Wall -werror?
No, I am sure GazL means to check the runtime return value from the calls to scanf() and malloc() to be certain they succeeded, as opposed to compile time flags.


Quote:
Originally Posted by ajiten View Post
Also, my attempt on void pointer being used for passing array as a parameter, are based on finding a complete code to the program for Quicksort code, given incomplete in the book: Algorithms in a nutshell, by George T. Heineman.
Then the caller will determine the type by choosing the comparator function to be called (your not yet implemented cmp() functions). Generally a qsort() function will expect two void pointers and a function pointer. The function being passed will know how to cast the void pointers and perform their comparison, and will return a value to indicate whether a swap is to be performed or not. So use of void* pointers allows a single sort function to accept pointers to different types (i.e. void*s) and corresponding comparator functions.

Quote:
Originally Posted by ajiten View Post
Kindly tell if need to frame a new question, or is it fine, to ask about the construction of the cmp function, here?
It is preferred that you keep discussion of related questions in the same thread. Doing so makes it much easier for others to follow the overall context of the discussion and helps future visitors looking for solutions to similar problems. Thanks for asking!
 
Old 06-19-2023, 01:27 AM   #8
ajiten
Member
 
Registered: Jun 2023
Posts: 375

Original Poster
Rep: Reputation: 4
Quote:
Originally Posted by astrogeek View Post
...
Then the caller will determine the type by choosing the comparator function to be called (your not yet implemented cmp() functions). Generally a qsort() function will expect two void pointers and a function pointer. The function being passed will know how to cast the void pointers and perform their comparison, and will return a value to indicate whether a swap is to be performed or not. So use of void* pointers allows a single sort function to accept pointers to different types (i.e. void*s) and corresponding comparator functions.



It is preferred that you keep discussion of related questions in the same thread. Doing so makes it much easier for others to follow the overall context of the discussion and helps future visitors looking for solutions to similar problems. Thanks for asking!
Request some 'more' hints for building the cmp (comparator) function.

Also, the sortPointers() has the first parameter, passed to by the (yet to be built) main(), as the array using a double indirection pointer; so should the book's code be changed accordingly?

Seems the book code, has unnecessary passing of the cmp() as parameter, to all of the three functions.
Working on this aspect first, as cmp() can be called by the function partition() alone, and there seems no need to pass it as a function parameter, to all of the 3 functions given in the book.
Also, the first function of the book, i.e. void sortPointers(void **vals, int total_elems, int(*cmp)(const void *, const void *)), seems redundant.
Also, the use of passing the selectPivotIndex(), the array seems useless, as it will have a superficial functionality for finding the pivot; rather than sorting the array; which is a function tp be implemented by the whole program itself.
If so, then there is no need for a selectPivotIndex() function even; as can choose if the pivot is the median element, or the left end, or the right end element; in the do_q_sort() function itself.

Last edited by ajiten; 06-19-2023 at 03:10 AM.
 
Old 06-19-2023, 04:06 AM   #9
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,863

Rep: Reputation: 7311Reputation: 7311Reputation: 7311Reputation: 7311Reputation: 7311Reputation: 7311Reputation: 7311Reputation: 7311Reputation: 7311Reputation: 7311Reputation: 7311
I would suggest you to run debugger like ddd to see how does your code work.
 
Old 06-19-2023, 05:31 AM   #10
GazL
LQ Veteran
 
Registered: May 2008
Posts: 6,897

Rep: Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019Reputation: 5019
The use of a comparator function pointer is to provide a more general sort function that can be used on many base types, by simply passing a different function as an argument. Rather than go over it here, I'll post this link which will give you some clues.

https://www.cprogramming.com/tutoria...-pointers.html

If you google "C function pointers" you'll find lots of articles on this topic. Many of which mention comparison functions as that's a very common use case for them

Hope that helps.


And, yes, Astrogeek was spot on with what I meant above checking return values.
 
Old 06-21-2023, 12:30 PM   #11
ajiten
Member
 
Registered: Jun 2023
Posts: 375

Original Poster
Rep: Reputation: 4
Quote:
Originally Posted by GazL View Post
scanf expects a pointer. array + i evaluates to a pointer, while array[i] evaluates to the value of the base type being pointed to. i.e. there's an implicit dereference operation.

((int *)arr)[i] - cast arr to an int pointer type.
((int *)arr)[i] - apply subscript and evaluate to the value stored at that memory location.

parenthesis are needed because of operator precedence [] is higher than (cast). To get the address you need the address-of operator & e.g.
&((int *)arr)[i]

[] has higher precedence than & so no additional parenthesis are required.

But, honestly this is ugly and you can do it much cleaner:
Code:
#include <stdio.h>
#include <stdlib.h>
int main(){
    void *mem;
    int n;
    int sum = 0;
    scanf("%d", &n);
    mem = malloc(n*sizeof(int)); //malloc returns a void pointer to the array's starting index, to arr.

    for ( int *p = (int *)mem, *end = p + n ; p < end; p++ )
        scanf("%d", p);

    for ( int *p = (int *)mem, *end = p + n ; p < end; p++ )
        sum += *p;

    free(mem);

    printf("%d", sum);
}
That said, unless you're planning to reuse the malloc'd memory for different purposes in your program, probably best just to use the right pointer type to start with as ntubski has pointed out.

P.S. I didn't bother adding them on the above example, but don't forget to check the returns on malloc() and scanf() to catch error conditions.
Have the Quicksort program, in which had to implement only the main, cmp(comparator), & selectPivotIndex functions.
Rest program functions are copied from the book: Algorithms in a nutshell, by George T. Heineman.
Have built the following code:

Code:
#include <stdio.h>
#include<stdlib.h>
int partition(void **, int, int *, int, int , int);
int cmp(const void *, const void*);
void do_qsort(void **, int *, int, int);
int selectPivotIndex(void **, int, int);

int main(){
	void ** vals;//array of pointers
        int total_elements;
	printf("How many elements in the array");
	scanf("%d", total_elements);
	vals = malloc(total_elements*sizeof(int));
	for(int i=0; i<total_elements; i++) scanf("%d", (int *)vals+i);
        for(int **p=(int **)vals, **end = p+total_elements; **p<total_elements; p++)
		scanf("%d", *p);
	return do_qsort(vals, int (* cmp)(const void *, const void*), 0, total_elements-1);
}

void do_qsort(void **ar, int(*cmp)(const void *, const void *), int left, int right){
	int pivotIndex;
	if (right<= left) return;
        pivotIndex = selectPivotIndex(ar, left, right);
	pivotIndex = partition(ar, cmp, left, right, pivotIndex);
	do_qsort(ar, cmp, left, pivotIndex-1);  do_qsort(ar, cmp, pivotIndex+1, right);
}

int partition(void ** ar, int(* cmp)(const void*, const void*), int left, int right, int pivotIndex){
       int idx, store; void *pivot = ar[pivotIndex]; void *tmp = ar[right]; 
       ar[right] = ar[pivotIndex];  ar[pivotIndex]= tmp;
       store = left;
       for(idx= left; idx<right;idx++){
	       if(cmp(ar[idx], pivot) <=0){
	              tmp = ar[idx]; ar[idx]=ar[store]; ar[store]=tmp; store++;
	       }
       }
       tmp= ar[right];  ar[right] = ar[store];  ar[store] = tmp;

       return store;
}

int cmp(const void * a, const void *b)
{
      if ((int*)a<=(int*)b)  return 0;
      else return 1;
}

int selectPivotIndex(void ** ar, int left, int right)
{
      int median;
      median = (left+right)/2;
      if(median %2==0) median = median +1;
      return median;
}
Have compiled, on Cygwin, using the option:
Code:
 gcc --save-temps --verbose quicksort.c -o  quicksort
Though, once the errors subside, will use the option:
Code:
 cc -pedantiC -W -Wall -Werror quicksort.c -o quicksort
Have got many errors, as shown below:

Code:
quicksort.c: In function ‘main’:
quicksort.c:17:31: error: expected expression before ‘int’
   17 |         return do_qsort(vals, int (* cmp)(const void *, const void*), 0, total_elements-1);
      |                               ^~~
quicksort.c:17:16: error: too few arguments to function ‘do_qsort’
   17 |         return do_qsort(vals, int (* cmp)(const void *, const void*), 0, total_elements-1);
      |                ^~~~~~~~
quicksort.c:5:6: note: declared here
    5 | void do_qsort(void **, int *, int, int);
      |      ^~~~~~~~
quicksort.c: At top level:
quicksort.c:20:6: error: conflicting types for ‘do_qsort’; have ‘void(void **, int (*)(const void *, const void *), int,  int)’
   20 | void do_qsort(void **ar, int(*cmp)(const void *, const void *), int left, int right){
      |      ^~~~~~~~
quicksort.c:5:6: note: previous declaration of ‘do_qsort’ with type ‘void(void **, int *, int,  int)’
    5 | void do_qsort(void **, int *, int, int);
      |      ^~~~~~~~
quicksort.c: In function ‘do_qsort’:
quicksort.c:24:36: warning: passing argument 2 of ‘partition’ makes integer from pointer without a cast [-Wint-conversion]
   24 |         pivotIndex = partition(ar, cmp, left, right, pivotIndex);
      |                                    ^~~
      |                                    |
      |                                    int (*)(const void *, const void *)
quicksort.c:3:24: note: expected ‘int’ but argument is of type ‘int (*)(const void *, const void *)’
    3 | int partition(void **, int, int *, int, int , int);
      |                        ^~~
quicksort.c:24:41: warning: passing argument 3 of ‘partition’ makes pointer from integer without a cast [-Wint-conversion]
   24 |         pivotIndex = partition(ar, cmp, left, right, pivotIndex);
      |                                         ^~~~
      |                                         |
      |                                         int
quicksort.c:3:29: note: expected ‘int *’ but argument is of type ‘int’
    3 | int partition(void **, int, int *, int, int , int);
      |                             ^~~~~
quicksort.c:24:22: error: too few arguments to function ‘partition’
   24 |         pivotIndex = partition(ar, cmp, left, right, pivotIndex);
      |                      ^~~~~~~~~
quicksort.c:3:5: note: declared here
    3 | int partition(void **, int, int *, int, int , int);
      |     ^~~~~~~~~
quicksort.c:25:78: error: expected expression before ‘,’ token
   25 |         do_qsort(ar, cmp, left, pivotIndex-1);  do_qsort(ar, cmp, pivotIndex+!, right);
      |                                                                              ^
quicksort.c: At top level:
quicksort.c:28:5: error: conflicting types for ‘partition’; have ‘int(void **, int (*)(const void *, const void *), int,  int,  int)’
   28 | int partition(void ** ar, int(* cmp)(const void*, const void*), int left, int right, int pivotIndex){
      |     ^~~~~~~~~
quicksort.c:3:5: note: previous declaration of ‘partition’ with type ‘int(void **, int,  int *, int,  int,  int)’
    3 | int partition(void **, int, int *, int, int , int);
Starting with the first two errors, failed to make any sense out of the same.
The first error asks for an expression before 'int', while the second complains about too few arguments passed to the do_qsort(), by the main()?

Last edited by ajiten; 06-21-2023 at 12:52 PM.
 
Old 06-21-2023, 02:05 PM   #12
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,866
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
Start with line 5: it should be:
Code:
void do_qsort(void **ar, int(*cmp)(const void *, const void *), int left, int right);
Then line 17:
Code:
- return do_qsort(vals, int (* cmp)(const void *, const void*), 0, total_elements-1);
+ return do_qsort(vals, cmp, 0, total_elements-1);

Last edited by NevemTeve; 06-21-2023 at 02:08 PM.
 
1 members found this post helpful.
Old 06-21-2023, 08:01 PM   #13
ajiten
Member
 
Registered: Jun 2023
Posts: 375

Original Poster
Rep: Reputation: 4
Quote:
Originally Posted by NevemTeve View Post
Start with line 5: it should be:
Code:
void do_qsort(void **ar, int(*cmp)(const void *, const void *), int left, int right);
Then line 17:
Code:
- return do_qsort(vals, int (* cmp)(const void *, const void*), 0, total_elements-1);
+ return do_qsort(vals, cmp, 0, total_elements-1);
Seems the modification needs to be applied, for the prototype declaration, where the passed passed parameters are functions, i.e. for the partition() too.

It seems logical, but if there is a name for this case involving functions being passed as parameters, please tell.

Also, I compiled with the option, as given in a book:
Code:
gcc --save-temps --verbose quicksort.c -o  quicksort> quicksort.txt
Though, with the below option, have errors that don't know of how to remove.
Code:
cc -pedantic -W -Wall -Werror quicksort.c -o quicksort1

Code:
User@DESKTOP-OKV7A0Q ~
$ cc -pedantic -W -Wall -Werror quicksort.c -o quicksort1
quicksort.c: In function ‘main’:
quicksort.c:17:37: error: unused variable ‘end’ [-Werror=unused-variable]
   17 |         for(int **p=(int **)vals, **end = p+total_elements; **p<total_elements; p++)
      |                                     ^~~
quicksort.c: In function ‘selectPivotIndex’:
quicksort.c:51:30: error: unused parameter ‘ar’ [-Werror=unused-parameter]
   51 | int selectPivotIndex(void ** ar, int left, int right)
      |                      ~~~~~~~~^~
cc1: all warnings being treated as errors
The complete code is:
Code:
#include <stdio.h>
#include<stdlib.h>
//int partition(void **, int, int *, int, int , int);
int partition(void ** ar, int(* cmp)(const void*, const void*), int left, int right, int pivotIndex);
int cmp(const void *, const void*);
//void do_qsort(void **, int *(const void *, const void*), int, int);
void do_qsort(void **ar, int(*cmp)(const void *, const void *), int left, int right);
int selectPivotIndex(void **, int, int);

int main(){
	void ** vals;//array of pointers
        int total_elements;
	printf("How many elements in the array");
	scanf("%d", &total_elements);
	vals = malloc(total_elements*sizeof(int));
	for(int i=0; i<total_elements; i++) scanf("%d", (int *)vals+i);
        for(int **p=(int **)vals, **end = p+total_elements; **p<total_elements; p++)
		scanf("%d", *p);
	do_qsort(vals, cmp, 0, total_elements-1);
        return 1;
}

void do_qsort(void **ar, int(*cmp)(const void *, const void *), int left, int right){
	int pivotIndex;
	if (right<= left) return;
        pivotIndex = selectPivotIndex(ar, left, right);
	pivotIndex = partition(ar, cmp, left, right, pivotIndex);
	do_qsort(ar, cmp, left, pivotIndex-1);  do_qsort(ar, cmp, pivotIndex+1, right);
}

int partition(void ** ar, int(* cmp)(const void*, const void*), int left, int right, int pivotIndex){
       int idx, store; void *pivot = ar[pivotIndex]; void *tmp = ar[right]; 
       ar[right] = ar[pivotIndex];  ar[pivotIndex]= tmp;
       store = left;
       for(idx= left; idx<right;idx++){
	       if(cmp(ar[idx], pivot) <=0){
	              tmp = ar[idx]; ar[idx]=ar[store]; ar[store]=tmp; store++;
	       }
       }
       tmp= ar[right];  ar[right] = ar[store];  ar[store] = tmp;

       return store;
}

int cmp(const void * a, const void *b)
{
      if ((int*)a<=(int*)b)  return 0;
      else return 1;
}

int selectPivotIndex(void ** ar, int left, int right)
{
      int median;
      median = (left+right)/2;
      if(median %2==0) median = median +1;
      return median;
}
Want to add that it was more interesting to see how the compiler works, in terms of reporting errors, as earlier; but don't how to dive into that topic.

Say, to the simplest, if in the code above the line: "scanf("%d", &total_elements);" is changed to: "scanf("%d", total_elements);" two errors appear; of which the second error is more interesting, as to why it vanishes on reading the address of the variable: total_elements.
Code:
error: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘int’ [-Werror=format=]
   14 |         scanf("%d", total_elements);
      |                ~^   ~~~~~~~~~~~~~~
      |                 |   |
      |                 |   int
      |                 int *

error: ‘total_elements’ is used uninitialized [-Werror=uninitialized]
  14 |         scanf("%d", total_elements);
     |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~

Last edited by ajiten; 06-21-2023 at 08:27 PM.
 
Old 06-21-2023, 11:42 PM   #14
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,866
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
If an object is marked as `unused`, you should check why that object exists. In your `main` function the second for-loop can be removed.
Think of it this pointer based storing is a complete waste of memory when sorting integers. Nonetheless here is a possible method:
Code:
        scanf("%d", &total_elements);
	int *intvals = malloc(total_elements*sizeof(int));
	for(int i=0; i<total_elements; i++) scanf("%d", &intvals[i]);
        int **vals = malloc(total_elements*sizeof(int *));
        for(int i=0; i<total_elements; i++) vals[i]= &intvals[i];
        do_qsort((void **)vals, cmp, 0, total_elements-1);
        for(int i=0; i<total_elements; i++) printf("%d\n", *vals[i]);
 
1 members found this post helpful.
Old 06-22-2023, 09:56 AM   #15
ajiten
Member
 
Registered: Jun 2023
Posts: 375

Original Poster
Rep: Reputation: 4
Quote:
Originally Posted by NevemTeve View Post
If an object is marked as `unused`, you should check why that object exists. In your `main` function the second for-loop can be removed.
Think of it this pointer based storing is a complete waste of memory when sorting integers. Nonetheless here is a possible method:
Code:
        scanf("%d", &total_elements);
	int *intvals = malloc(total_elements*sizeof(int));
	for(int i=0; i<total_elements; i++) scanf("%d", &intvals[i]);
        int **vals = malloc(total_elements*sizeof(int *));
        for(int i=0; i<total_elements; i++) vals[i]= &intvals[i];
        do_qsort((void **)vals, cmp, 0, total_elements-1);
        for(int i=0; i<total_elements; i++) printf("%d\n", *vals[i]);
Sorry, but having extra separate array should increase the space needed instead. So, how the waste of memory for sorting integers, using pointer based sorting; is happening, and avoided by your approach is unclear.
Please tell any measure of the memory used, using any command to elaborate the same, if possible.

Also, for my silly question, that can have the below solution.
Code:
#include <stdio.h>
#include<stdlib.h>
//int partition(void **, int, int *, int, int , int);
int partition(void ** ar, int(* cmp)(const void*, const void*), int left, int right, int pivotIndex);
int cmp(const void *, const void*);
//void do_qsort(void **, int *(const void *, const void*), int, int);
void do_qsort(void **ar, int(*cmp)(const void *, const void *), int left, int right);
int selectPivotIndex(int, int);

int main(){
	void ** vals;//array of pointers
        int total_elements;
	printf("How many elements in the array");
	scanf("%d", &total_elements);
	vals = malloc(total_elements*sizeof(int));
	for(int i=0; i<total_elements; i++) scanf("%d", (int *)vals+i);
        //for(int **p=(int **)vals, **end = p+total_elements; **p<total_elements; p++)
	for(int **p=(int **)vals; **p<total_elements; p++)
		scanf("%d", *p);
	do_qsort(vals, cmp, 0, total_elements-1);
        return 1;
}

void do_qsort(void **ar, int(*cmp)(const void *, const void *), int left, int right){
	int pivotIndex;
	if (right<= left) return;
        pivotIndex = selectPivotIndex(left, right);
	pivotIndex = partition(ar, cmp, left, right, pivotIndex);
	do_qsort(ar, cmp, left, pivotIndex-1);  do_qsort(ar, cmp, pivotIndex+1, right);
}

int partition(void ** ar, int(* cmp)(const void*, const void*), int left, int right, int pivotIndex){
       int idx, store; void *pivot = ar[pivotIndex]; void *tmp = ar[right]; 
       ar[right] = ar[pivotIndex];  ar[pivotIndex]= tmp;
       store = left;
       for(idx= left; idx<right;idx++){
	       if(cmp(ar[idx], pivot) <=0){
	              tmp = ar[idx]; ar[idx]=ar[store]; ar[store]=tmp; store++;
	       }
       }
       tmp= ar[right];  ar[right] = ar[store];  ar[store] = tmp;

       return store;
}

int cmp(const void * a, const void *b)
{
      if ((int*)a<=(int*)b)  return 0;
      else return 1;
}

int selectPivotIndex(int left, int right)
{
      int median;
      median = (left+right)/2;
      if(median %2==0) median = median +1;
      return median;
}

Last edited by ajiten; 06-22-2023 at 10:40 AM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Unable to pass array as parameter, using void pointer, s.t. the contents too are accessed in the called function. ajiten Programming 19 06-18-2023 07:52 PM
pthread giving error: invalid conversion from ‘void* (*)(int*)’ to ‘void* (*)(void*)’ knobby67 Programming 4 05-05-2017 10:54 AM
read any given maze.txt into an internal dynamically allocated array of strings. jack555 Programming 4 04-27-2011 01:31 AM
In C, using qsort for dynamically allocated array ntmsz Programming 7 08-23-2005 10:33 AM
void foo(void) and void foo() lackluster Programming 9 02-15-2003 10:57 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 11:23 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration