Alright so i'll try to explain my problem clearly.
I would like to have a function which would sort an array of anything, based on the size of an element and on the offset and the size of the the variable in an element (for use with structures).
So my function would look like:
void sort(void* array, size_t elem_size, int elem_count, size_t operand_offset, size_t operand_size)
array is a pointer to the beginning of the array
elem_size is the size of one element in the array
elem_count is the count of elements in the array
operand_offset is the offset of the variable within the element to base the sort on (it would be 0 if the element is only one variable, but it could be more if the element is a struct)
operand_size is the size of that variable
In this function i need to create a temp variable, i would do it like that:
void* temp = malloc(elem_size);
*temp = *(array+ i*elem_size);
but the compiler doesn't agree: dereferencing void* pointer, and he doesn't know the size of my temp variable...
I know i could do it byte per byte, but i would like to know if there is a better way.
So my question is:
How to set the "size" of a pointer to elem_size ?
Aditional question:
Could i type array[i] to access an element if the size is known ?
EDIT
Ok so my problem is solved i must use memcpy
But now i have another problem i didn't expect.
Given the size and the offset of the operand within the element, how could i extract it and compare it?
kinda like:
void *a = malloc(operand_size);
void *b = malloc(operand_size);
memcpy(a, array+i*elem_size + operand_offset, operand_size);
memcpy(b, array+j*elem_size + operand_offset, operand_size);
if (a < b)
...
else
...
How can i do that?
*EDIT 2: *
Well, finally it was too complicated managing an if statement for each size of operand, so i did something completely different
So basically i had a void *array containing n elements, and i was writing a function to sort it.
But instead of giving directly the offset and the size of the operand within the element, i gave the function another function to compare two elements. That works well
int compareChar(void* a, void* b);
int compareShort(void* a, void* b);
int compareInt(void* a, void* b);
int compareLong(void* a, void* b);
int compareFOO(void* a, void* b);
void sort(void* array, size_t elem_size, int elem_count, int (*compare)(void*,void*));
Couldn't you just use memcpy? That will likely do it in the most efficient manner.
uint8_t* temp = malloc(elem_size);
memcpy(temp, array + i * elem_size, elem_size);
Related
I am learning C from "C by K&R". I was going through Function pointers section.There was an example to sort an array of strings using function pointers and void pointers.(to be specific,on page 100). I have a fair understanding of function pointers and void pointers.
The example given there calls
qsort((void**) lineptr, 0, nlines-1,(int (*)(void*,void*))(numeric ? numcmp : strcmp));
And it seemlessly uses void ptr,like as below to compare and swap.
I understand that it takes array of pointer and each element by itself is a void pointer to the string. How is it possible to compare,swap a void ptr with another.
void sort(void *v[],int i,int j)
{
id *temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
Can anyone explain the concept behind this.
How is it possible to compare, swap a void ptr with another?
Compare: comparing a void ptr with each other is meaningless, as their values are addresses.
Swap: A pointer is a variable holding an address. By changing a pointer's value you change the address it points to. Data itself is not even considered here.
Note: void pointers does not interpret the data they are pointing to. That is why you need explicit type conversion when you dereference them, such that there is a correspondence between the data they are pointing to and the variable this data is assign to.
Remember that pointers are just variables that store a memory address. If there's not any conflict between types I can't see why this shouldn't be possible!
The only difference between a void ptr and another is that you must pay attention only during the dereference (you need a cast to complete it)
For example:
void *ptr;
int m, n;
ptr = &n;
m = *((int *) ptr);
Anyway, ignoring this particular, you can work with void pointer normally.. You can, as your code shows, for example swap them just as they were int or other types variables
The function pointer required by qsort() has the following type
int (*compar)(const void *, const void *);
it means, that you can pass pointers of any type to this function since in c void * is converted to any poitner type without a cast.
Inside a comparision funcion, you MUST "cast"1 the void * poitners in order to be able to dereference them. Because a void * pointer cannot be dereferenced.
Swaping pointers is the correct way to sort an array of poitners, just like swaping integers would be the way to sort an array of integers. The other way, with an array of strings for example, would be to copy the string to a temporary buffer and perform a swap in terms of copying the data, and I think there is no need to explain why this is bad.
1
When I say cast I don't mean that you need to "cast", just convert to the appropriate poitner type. For example:
int compare_integers(const void *const x, const void *const y)
{
int *X;
int *Y;
X = x;
Y = y;
return (*X - *Y);
}
although it's of course possible to write return (*((int *) x) - *((int *) y)).
In this type of situation, it's often helpful to typedef to gain a better understanding. For illustration purposes, you could do
typedef void* address; //to emphasize that a variable of type void* stores an address
Now your swap function looks less daunting,
void swap(address v[],int i,int j) //takes an array of addresses v
{
address temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
A void *, however, contains no information regarding the type of object it points to. So before dereferencing it, you need to cast it to the right type, which is what strcmp and numcmp do, e.g.,
int strcmp(address a1, address a2) { //assumes a1 and a2 store addresses of strings
char *s1 = a1;
char *s2 = a2;
//s1 and s2 can be dereferenced and the strings they point to can be compared
}
So... I have a dynamically allocated array on my main:
int main()
{
int *array;
int len;
array = (int *) malloc(len * sizeof(int));
...
return EXIT_SUCCESS;
}
I also wanna build a function that does something with this dynamically allocated array.
So far my function is:
void myFunction(int array[], ...)
{
array[position] = value;
}
If I declare it as:
void myFunction(int *array, ...);
Will I still be able to do:
array[position] = value;
Or I will have to do:
*array[position] = value;
...?
Also, if I am working with a dynamically allocated matrix, which one is the correct way to declare the function prototype:
void myFunction(int matrix[][], ...);
Or
void myFunction(int **matrix, ...);
...?
If I declare it as:
void myFunction(int *array, ...);
Will I still be able to do:
array[position] = value;
Yes - this is legal syntax.
Also, if I am working with a dynamically allocated matrix, which one
is correct to declare the function prototype:
void myFunction(int matrix[][], ...);
Or
void myFunction(int **matrix, ...);
...?
If you're working with more than one dimension, you'll have to declare the size of all but the first dimension in the function declaration, like so:
void myFunction(int matrix[][100], ...);
This syntax won't do what you think it does:
void myFunction(int **matrix, ...);
matrix[i][j] = ...
This declares a parameter named matrix that is a pointer to a pointer to int; attempting to dereference using matrix[i][j] will likely cause a segmentation fault.
This is one of the many difficulties of working with a multi-dimensional array in C.
Here is a helpful SO question addressing this topic:
Define a matrix and pass it to a function in C
Yes, please use array[position], even if the parameter type is int *array. The alternative you gave (*array[position]) is actually invalid in this case since the [] operator takes precedence over the * operator, making it equivalent to *(array[position]) which is trying to dereference the value of a[position], not it's address.
It gets a little more complicated for multi-dimensional arrays but you can do it:
int m = 10, n = 5;
int matrixOnStack[m][n];
matrixOnStack[0][0] = 0; // OK
matrixOnStack[m-1][n-1] = 0; // OK
// matrixOnStack[10][5] = 0; // Not OK. Compiler may not complain
// but nearby data structures might.
int (*matrixInHeap)[n] = malloc(sizeof(int[m][n]));
matrixInHeap[0][0] = 0; // OK
matrixInHeap[m-1][n-1] = 0; // OK
// matrixInHeap[10][5] = 0; // Not OK. coloring outside the lines again.
The way the matrixInHeap declaration should be interpreted is that the 'thing' pointed to by matrixInHeap is an array of n int values, so sizeof(*matrixInHeap) == n * sizeof(int), or the size of an entire row in the matrix. matrixInHeap[2][4] works because matrixInHeap[2] is advancing the address matrixInHeap by 2 * sizeof(*matrixInHeap), which skips two full rows of n integers, resulting in the address of the 3rd row, and then the final [4] selects the fifth element from the third row. (remember that array indices start at 0 and not 1)
You can use the same type when pointing to normal multidimensional c-arrays, (assuming you already know the size):
int (*matrixPointer)[n] = matrixOnStack || matrixInHeap;
Now lets say you want to have a function that takes one of these variably sized matrices as a parameter. When the variables were declared earlier the type had some information about the size (both dimensions in the stack example, and the last dimension n in the heap example). So the parameter type in the function definition is going to need that n value, which we can actually do, as long as we include it as a separate parameter, defining the function like this:
void fillWithZeros(int m, int n, int (*matrix)[n]) {
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
matrix[i][j] = 0;
}
If we don't need the m value inside the function, we could leave it out entirely, just as long as we keep n:
bool isZeroAtLocation(int n, int (*matrix)[n], int i, int j) {
return matrix[i][j] == 0;
}
And then we just include the size when calling the functions:
fillWithZeros(m, n, matrixPointer);
assert(isZeroAtLocation(n, matrixPointer, 0, 0));
It may feel a little like we're doing the compilers work for it, especially in cases where we don't use n inside the function body at all (or only as a parameter to similar functions), but at least it works.
One last point regarding readability: using malloc(sizeof(int[len])) is equivalent to malloc(len * sizeof(int)) (and anybody who tells you otherwise doesn't understand structure padding in c) but the first way of writing it makes it obvious to the reader that we are talking about an array. The same goes for malloc(sizeof(int[m][n])) and malloc(m * n * sizeof(int)).
Will I still be able to do:
array[position] = value;
Yes, because the index operator p[i] is 100% identical to *(ptr + i). You can in fact write 5[array] instead of array[5] and it will still work. In C arrays are actually just pointers. The only thing that makes an array definition different from a pointer is, that if you take a sizeof of a "true" array identifier, it gives you the actual storage size allocates, while taking the sizeof of a pointer will just give you the size of the pointer, which is usually the system's integer size (can be different though).
Also, if I am working with a dynamically allocated matrix, which one is the correct way to declare the function prototype: (…)
Neither of them because those are arrays of pointers to arrays, which can be non-contigous. For performance reasons you want matrices to be contiguous. So you just write
void foo(int matrix[])
and internally calculate the right offset, like
matrix[width*j + i]
Note that writing this using the bracket syntax looks weird. Also take note that if you take the sizeof of an pointer or an "array of unspecified length" function parameter you'll get the size of a pointer.
No, you'd just keep using array[position] = value.
In the end, there's no real difference whether you're declaring a parameter as int *something or int something[]. Both will work, because an array definition is just some hidden pointer math.
However, there's is one difference regarding how code can be understood:
int array[] always denotes an array (it might be just one element long though).
int *pointer however could be a pointer to a single integer or a whole array of integers.
As far as addressing/representation goes: pointer == array == &array[0]
If you're working with multiple dimensions, things are a little bit different, because C forces you declare the last dimension, if you're defining multidimensional arrays explicitly:
int **myStuff1; // valid
int *myStuff2[]; // valid
int myStuff3[][]; // invalid
int myStuff4[][5]; // valid
I'm wondering if there any method to get the number of element in an Array like Array#size in ruby, so I come up with
int a;
int ary[] = {1,2,3,4,5,6};
int number_of_elements =sizeof(ary)/sizeof(a);
for(index = 0;index < number_of_element);index++){
printf("the %d element of array is %d",index,*(ptr + index));
}
it works, but I want a more elegant way to do this.
Well, you can use this macro.
#define N_ELEM(t) (sizeof(t) / sizeof(*t))
Isn't it elegant ?
(Of course, it doens't work with dynamic arrays)
No, there's no easy way to count the number of elements in an array in C unless you provide your own delimiter value to indicate the end of the array (similar as to how '\0' is used in strings.)
There might be a more elegant solution than this too.
#define number_of_elements sizeof(arr)/sizeof(arr[0])
or
const int number_of_elements = sizeof(arr)/sizeof(arr[0])
Also do look at:
How to find the 'sizeof' (a pointer pointing to an array)?
There is no elegant or easy way, and even the sizeof trick has limits; when an array expression is passed to a function, what the function receives is a pointer value, not an array. So something like
void foo(int a[])
{
size_t count = sizeof a / sizeof a[0];
...
}
won't work because in the context of a function parameter declaration, T a[] and T a[N] are identical to T *a; a is a pointer value, not an array, so you get the size of a pointer to int divided by the size of the first element, which is not what you want.
Basically, you have to keep track of the array's size yourself. You know how big it is when you create it, so you have to preserve that information and pass it with the array:
void foo(int *a, size_t asize)
{
...
}
int main(void)
{
int arr[SOME_SIZE];
...
foo(arr, SOME_SIZE);
...
}
I'm writing a function that returns the size of ints array. The logic is: sizeof(arr) / sizeof(int); it worked fine if I save it to an variable, but if I return it to a function, I get 1for an array with 10 bytes of size. Why? here is my code:
int b[10];
int t1= sizeof (b) / sizeof (int);
size_t t2 = lenof(b);
printf("t1 = %d, t2 = %d\n", t1, t2);
size_t lenof (int arr[]) { return sizeof (arr) / sizeof (int); }
the above C code prints:
t1 = 10, t2 = 1
someone can explain for me please? maybe should I do it using pointers? Thanks.
Scenario 1:
int t1= sizeof (b) / sizeof (int);
In this case, sizeof(b) returns the size of the array, which divided by the size of int yields number of array elements correctly.
Scenario 2:
When you pass array to a function it decays as a pointer to the first element in the array.Hence,
lenof(int arr[])
is actually exactly equivalent to:
lenof(int *arr)
GIven that, sizeof (arr) yields size of an pointer on your system & that size it seems is same as size of int on your system and hence the division and the function returns 1.
C does not provide bounds checking for arrays, So you will never be warned if you write beyonds the array bounds. This essentially means wheile using arrays, You have to keep track of how many elements are present in the array yourself.
If you need the size of array inside a function simplest solution is to pass the size of the array as a separate parameter.
lenof(int arr[], int len);
I'm trying to swap objects for a homework problem that uses void pointers to swap objects. The declaration of my function has to be:
void swap(void *a, void *b, size_t size);
I'm not looking for the exact code how to do it so I can figure it out by myself, but I'm not sure if I understand it correctly. I found that one problem is by doing:
void *temp;
temp = a;
a = b;
b = temp;
only changes what the pointers point to. Is that correct? If it is correct, why doesn't swapping pointers actually change the contents between *a and *b. Because if your pointer points to something different, couldn't you dereference it and the objects would now be different?
Similarly, just switching the values like:
void *temp;
*temp = *a;
*a = *b;
*b = *temp;
Is not correct either, which I'm not sure why. Because again, it seems to me that the content is switched.
Does swapping objects mean complete swapping of memory and value of what a pointer points to?
So it seems like I have to use malloc to allocate enough space for my swap. If I allocate enough memory for one object, assuming they are the same size, I don't really see how it is different than the other two methods above.
void *temp = malloc(sizeof(pa));
// check for null pointer
temp = a;
// do something I'm not sure of since I don't quite get how allocating space is any
// different than the two above methods???
Thanks!
Swapping pointers does not change the pointed-to values. If it did, that would be like swapping address labels on envelopes moving me into your house and you into mine.
You were nearly there:
void swap(void *a, void *b, size_t size) {
char temp[size]; // C99, use malloc otherwise
// char serves as the type for "generic" byte arrays
memcpy(temp, b, size);
memcpy(b, a, size);
memcpy(a, temp, size);
}
The memcpy function copies memory, which is the definition of objects in C. (Called POD or plain ol' data in C++, to compare.) In this way, memcpy is how you do assignment without caring about the type of the object, and you could even write other assignments as memcpy instead:
int a = 42, b = 3, temp;
temp = b;
b = a;
a = temp;
// same as:
memcpy(&temp, &b, sizeof a);
memcpy(&b, &a, sizeof a);
memcpy(&a, &temp, sizeof a);
This is exactly what the above function does, since you cannot use assignment when you do not know the type of the object, and void is the type that stands in for "unknown". (It also means "nothing" when used as function return type.)
As a curiosity, another version which avoids malloc in common cases and doesn't use C99's VLAs:
void swap(void *a, void *b, size_t size) {
enum { threshold = 100 };
if (size <= threshold) {
char temp[threshold];
memcpy(temp, b, size);
memcpy(b, a, size);
memcpy(a, temp, size);
}
else {
void* temp = malloc(size);
assert(temp); // better error checking desired in non-example code
memcpy(temp, b, size);
memcpy(b, a, size);
memcpy(a, temp, size);
free(temp);
}
}
To answer your first question, let's fill in some values to see what is happening:
void* a = 0x00001000; // some memory address
void* b = 0x00002000; // another memory address
/* Now we'll put in your code */
void* temp; // temp is garbage
temp = a; // temp is now 0x00001000
a = b; // a is now 0x00002000
b = temp; // b is now 0x00001000
So at the end of those statements, the pointer's values have been swapped, that is, whatever a was pointing to is now pointed to by b, and vice versa. The values of what those pointers are pointing to are unmodified, it's just that now their memory addresses are being held by different pointers.
To answer your second question, you cannot dereference a void*. The reason for this is that void has no size, so to try and dereference or assign to something that has no size is nonsensical. Thus, void* is a way of guaranteeing you can point to something, but you will never know what that something is without more information (hence the size parameter to your routine).
From there, knowing the pointer and the size of the data the pointer points to, you can use a routine like memcpy to move the data pointed to by one pointer into the location pointed to by another.
Parameters are like local variables, with values copied into them before the function starts executing. This prototype:
void swap(void *a, void *b, size_t size);
Means that the two addresses are copied into new variables called a and b. So if you change what is stored in a and b, nothing you do will have an any effect after swap returns.
I had a question similar to this for my C course. I think memcopy is probably best but you can also try this:
typedef unsigned char * ucp;
void swap(void *a, void *b, int size){
ucp c=(ucp)a;
ucp d=(ucp)b;
for(int i=0; i<size; i++){
int temp=(int)c[i];
c[i]=(int)d[i];
d[i]=temp;
}
}
Basically what this does is cast both pointers to an unsigned char pointer type. Then you increment the pointer, which in the case of an unsigned char, increments one BYTE at a time. Then what you're doing is basically copying the contents of each byte at a time in memory. If anyone wants to correct or clarify on this I would appreciate it too.
First of all, note that any changes to the pointers inside the function won't be propagated to outside the function. So you're going to have to move memory around.
The easiest way to do that is with memcpy - allocate a buffer on the stack, memcpy the appropriate size from a into it, memcpy from b to a, and one last memcpy from temp into b.
If you were writing a function to swap two integers, given pointers to them, your solution of swapping the values pointed to would work. However, consider the situation with
struct {
int a;
int b;
} a, b;
swap(&a, &b, sizeof(a));
You need to figure out a way to swap the contents of each value passed without any knowledge of what they actually consist of.
You're close.
The problem is: you are "swapping" only pointers a and b which are local variables in the function.
I assume outside of the function you have some variables, let's call them:
void *x = ...;
void *y = ...;
When you call:
swap(x, y, some_size);
a and b points to the same objects as x and y respectively. Now, when you swap what a and b points too, x and y are still pointing to what they where pointing before.
To change what memory x and y points you would have to pass a pointer to the x variable, so a pointer to a pointer :)
Because you can't change function declaration you can only swap the content of the memory where x (and a) and y (and b) points to. Some solutions are in other answers :) Generally memcpy is what you want.
To have any real effect, you need to do the equivalent of the second block you mentioned:
void *temp;
*temp = *a;
*a = *b;
*b = *temp;
The problem here is that 'void' doesn't have a size, so you can't assign 'void's as they stand. You need to allocate space for temp to point at, then copy the values using something like memcpy().
To change the pointer inside and keep it outside, you have to pass the pointer by reference or a double pointer.
If your function has to be like:
void swap(void *a, void *b, size_t size);
I suppose that you have to implement something like:
void * temp;
temp = malloc(size);
memcpy(temp,a,size);
memcpy(a,b,size);
memcpy(b,temp,size);
free(temp);
We need not use memcpy for swapping two pointers, following code works well(tested for swapping int* and char* strings):
void swap(void **p, void **q)
{
void *t = *p;
*p = *q;
*q = t;
}