Unable to get proper output, using void pointer to store and read dynamically allocated array.
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
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.
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
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.
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.
...
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.
Quick partial answers, others feel free to elaborate...
Quote:
Originally Posted by ajiten
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
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
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!
...
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.
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.
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.
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;
}
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()?
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:
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);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
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:
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:
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;
}
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.