The man has the code
#include <conio.h>
#include <stdio.h>
void dbleInt(void *a) {
*((int*) a) *= 2;
}
void deleteEvenInt(void* a) {
int tmp = *((int*) a);
if (tmp % 2 == 0) {
*((int*) a) = 0;
}
}
void dbleDouble(void *a) {
*((double*) a) *= 2.0;
}
void deleteEvenDouble(void* a) {
int tmp = *((double*) a);
if (tmp % 2 == 0) {
*((double*) a) = 0;
}
}
// Function takes an array, its size, the size of one element and a function //pointer,
// Which is then applied to all the elements of an array
void map(void *arr, unsigned num, size_t size, void (*fun)(void *)) {
unsigned i;
char *ptr = (char*) arr;
for (i = 0; i < num; i++) {
fun((void*) (ptr + i*size));
}
}
Why does he leads void* type to char* type? I can see thats it an error, when I change this code and dont lead it, but why?
You're not allowed to perform arithmetic on void pointers in C. So the following code is illegal:
void *foo = whatever;
foo + 1;
By casting foo to a char *, she can perform arithmetic on the pointer.
My comments are on why void *ptr, one cannot perform address arithmetic. Warning , Long rambling :).
In general
when you do a ptr arithmetic like
ptr = ptr + N ;
The interpretation by C is to perform the following equivalent integer arithmetic (Infact the compiler will produce assembly code equivalent to below integer arithmetic)
ptr = ptr + N* sizeof (typeof(*N)) ;
Hence The compiler has to know the typeof (*N) for it to produce code. typeof (*N) here means, the type of variable "ptr" points to. (typeof is not a standard c construct, it is being bought here for mere explanation).
Take an e.g.
int x ; // Assume x is at addesss 1000
int *ptr = &x ; // ptr has a value of 1000
Then
ptr = ptr + 1 ;
would make ptr as 1004 during run time (assuming size of int is 4 bytes)
Explanation-1: The above statement means that ptr should contain the address of next integer variable after ptr. Since ptr points to x , which is at address 1000, the next integer variable after 1000 would be 1004. So ptr would be 1004.
Explanation-2 This is also in sync with the interpretation of ptr = ptr +N is equivalent to integer arithmeitc
ptr = ptr + N* sizeof (typeof(*N)) ; // typeof (*N)->int
// => 1000 + 1 *sizeof (typeof (int))
// => 1004
To summarize For the ptr arith operation
ptr = ptr + N ;
the compiler produces an equivalent assembly code as
ptr = ptr + N* sizeof (typeof(*N)) // Compiler Needs to typeof(*N)
Hence the compiler needs to know what is the data-type that ptr is pointing to.
Now consider
void foo (int type, void *ptr) {
ptr = ptr + 2 ;
}
f2() {
int x ;
char c ;
f1(&x) ;
f1(&c);
}
The void * ptr is a generic ptr pointing to an addresss. When called with f1(&x) the ptr points to an address of integer, when called with f1(&c) it points to address of a character. So at compile time , compiler cannot determine what is the typeof (*ptr). (for in one case it is integer and another is character). Hence it is not possible for the compiler to generate code for
ptr = ptr + n ;
So you will have to cast the ptr of being a particular known type and then do arithmetic operation.
Hope this helps.
Related
I was reading about function pointer. That it contains address of instructions. And there I encountered one question to find an element in array using function pointer. Here is the code.
#include <stdio.h>
#include <stdbool.h>
bool compare(const void* a, const void* b)
{
return (*(int*)a == *(int*)b);
}
int search(void* arr, int arr_size, int ele_size, void* x, bool compare(const void*, const void*))
{
char* ptr = (char*)arr; // Here why not int *ptr = (int*)arr;
int i;
for (i = 0; i < arr_size; i++)
{
if (compare(ptr + i * ele_size, x))
{
return i;
}
}
return -1;
}
int main()
{
int arr[] = { 2, 5, 7, 90, 70 };
int n = sizeof(arr) / sizeof(arr[0]);
int x = 7;
printf("Returned index is %d ", search(arr, n, sizeof(int), &x, compare));
return 0;
}
In the search function char *ptr = (char*)arr; is used which is giving perfect answer = 2.
But when I have used int *ptr = (int*)arr; it gives -1 as answer.
Why is this? Can anyone explain this?
A char is the smallest addressable unit in any C program, and on most system it corresponds to a single byte. That treats the array as a generic sequence of bytes, and uses the ele_size to calculate the byte-position of each element with ptr + i*ele_size.
If you use int *ptr then the byte-position calculation will be wrong by a factor of sizeof(int) (typically 4), since the pointer arithmetic will be done in units of the base type (int instead of char).
The function search knows nothing about what is the type of elements of the array pointed to by the pointer arr of the type void *.
So casting the pointer to the type int * does not make a sense. If to do so then the expression ptr + i*ele_size where the pointer arithmetic is used will produce an incorrect result.
That it contains address of instructions
There is a subtle difference between normal (object) pointers and function pointers. It is not possible to access the single instructions of a function - they do not have the same length.
With other pointers the increment (arithmetic) is adapted to the type, whether as p[i] or p + i or *(p+i).
Side note: there still is int at the bottom of the call chain:
return (*(int*)a == *(int*)b);
void * ptr = NULL; // array of unspecified 13-byte type
for (int i = 0; i < 10; i++) {
printf("%i ", ((char (*) [13]) ptr) + i);
}
putchar('\n');
Output:
0 13 26 39 52 65 78 91 104 117
So this works (at least on GCC) but how can I declare a variable of type (char (*) [13] so I wouldn't have to do that cast everytime I want to perform pointer arithmetic on that pointer?
And is this behavior even portable?
Pointer arithmetic of unspecified type with known size
And is this behavior even portable?
Strictly: maybe:
Need a deep dive into C17 6.3.2.3 Pointers
Something like below relies on the value of &fred[0] being able to convert to ptr without trouble. Many implementations will handle this without a problem, yet ptr is a pointer to an array, not a pointer to char. Had ptr been a pointer to char, no problem.
I think since ptr and fred both have the same alignment requirement - code is OK.
typedef something unspecified_13_byte_type;
assert(sizeof(unspecified_13_byte_type) == 13);
#define N
unspecified_13_byte_type fred[N];
char (*ptr)[13] = (void *) fred;
for (int i = 0; i < N; i++) {
// printf("%i ", ((char (*) [13]) ptr) + i);
printf("%p ", (void *) (((char (*) [13]) ptr) + i));
}
puts("");
Deeper: if something is some struct, then ptr and &fred[0] need not be the same encoding or even the same size - even if they well convert to and from each other and equate to each other. struct pointers and char * can be more different that usually expected - even if such differences are very uncommon today.
What do you mean? ptr wasn't even allocated. Casting it will result in undefined behavior.
You can either do this
void * ptr = malloc(10 * 13); // on heap
OR this
void * ptr = (char [10][13]){}; // on stack (C99)
It seems you mean something like the following
char s[10][13];
//…
void * ptr = s;
The array s used as an initializer is implicitly converted to pointer to its first element of the type char ( * )[13].
Or you could write
char s[10][13];
//…
char ( *tmp )[13] = s;
void * ptr = tmp;
Here is a demonstrative program that shows the pointer arithmetic
#include <stdio.h>
int main(void)
{
enum { N = 13 };
char s[][N] = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" };
const size_t M = sizeof( s ) / sizeof( *s );
void * ptr = s;
for ( size_t i = 0; i < M; i++ )
{
printf( "%s ", ( ( char ( * )[N] )ptr )[i] );
// or
// printf( "%s ", *( ( char ( * )[N] )ptr + i ) );
}
putchar( '\n' );
return 0;
}
Its output is
A B C D E F G H I J
I'm trying to pick my C skills again. I want to sum a sequence in different threads, each thread would return a pointer of the sum of a part of the sequence. However, when I tried to convert the void* type value local_sum to int, problem occurred.
I tried to convert with sum += *(int*)local_sum;, a segment error occurred and I got Process finished with exit code 11.
I found that if I use sum += (int)local_sum;, it would be okay. But I couldn't convince myself: shouldn't local_sum be a void *? Why it can be converted to int with (int)local_sum?
I'm so grateful it you could answer the problem.
The part that sum each process's return value is here:
int sum = 0;
for (int i = 0; i < NUM_THREADS; i ++) {
void * local_sum;
pthread_join(count_threads[i], (&local_sum));
sum += (int)local_sum;
}
The function of a thread is here:
void * count_thr(void *arg) {
int terminal = ARRAY_SIZE / NUM_THREADS;
int sum = 0;
for (int i = 0; i < terminal; i ++) {
sum += *((int*)arg + i);
}
return (void*)sum;
}
You're returning the value of int sum by setting a void * address to it. In this case, the address is not valid. But, if you keep that in mind and get the value of sum by casting a void * to int it will work.
void * is used this way sometimes to return either a value (e.g. int) or an address to something (e.g. struct).
To illustrate this:
int a = 5;
void *p = (void *)a;
int b = (int)p;
a, p, and b all have a value of 5. p does not point to a valid address. Trying to dereference p would result in undefined behavior:
b = *(int *)p; // Undefined Behavior!
Consider the following program:
#include <limits.h>
#include <stdio.h>
int main(void)
{
int a, b;
void *p;
a = 5;
p = (void *)a;
b = (int)p;
printf("%d %p %d\n", a, p, b);
a = INT_MAX;
p = (void *)a + 1;
b = (int)p;
printf("%d %p %d\n", a, p, b);
return 0;
}
When compiled, I get the following warnings:
$ gcc main.c -o main.exe
main.c: In function ‘main’:
main.c:9:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
p = (void *)a;
^
main.c:10:9: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
b = (int)p;
...
A warning is issued because, as pointed out by #Gerhardh, the sizeof(int) and the sizeof(void *) may be different. You may suffer data loss if the value of the void * exceeds the maximum value a int can hold.
Output
$ ./main.exe
5 0x5 5
2147483647 0x80000000 -2147483648
You can't do *(int*)local_sum because local_sum is not an int* cast to void*. local_sum is an int cast to void*. It is a number reinterpreted as an address, but only for transfer purposes, because pthread_exit only allows you to return a void*, not an int and because the standard explicitly allows implementation-defined conversion (6.3.2.3p5, 6.3.2.3p6) between integers and numbers as long as the values fit (if they don't then, UB). If you return, e.g., 0x42, it is highly unlikely there's anything at address 0x42, so you should forget about dereferencing it and instead you should convert it back to an integer ASAP, either with (int)local_sum; or perhaps better with (int)(intptr_t)local_sum; (though intptr_t isn't guaranteed to exist) or (perhaps best) with (int)(intmax_t)local_sum; so as to avoid possible compiler warnings about converting to an integer of a different size on LP64 platforms.
A secure and portable solution could be the use of an union:
union void_cast {
void* ptr;
int value;
};
Then for example you can safely reinterpret a void* pointer with:
int VOID_TO_INT(void* ptr) {
union void_cast u;
u.ptr = ptr;
return u.value;
}
void* INT_TO_VOID(int value) {
union void_cast u;
u.value = value;
return u.ptr;
}
So your code can be changed to:
sum += VOID_TO_INT(local_sum);
In a homework project, I have to subtract the address of one pointer from another.
Here is a piece of code I tried to write to subtract the heap of void* type, from a given metadata address. It's wrong somewhere.
metadata_t* getBuddy(metadata_t* ptr)
{
metadata_t* offset = ptr - (char)heap;
int h = (char)heap;
#ifdef DEBUG
printf("ptr : %p\n", ptr);
printf("heap : %p\n", heap);
printf("offset: %p\n", offset);
printf("char : %d\n", h);
#endif
return NULL;
}
Here is the output I get:
ptr : 0x7fe7b3802440
heap : 0x7fe7b3802200
offset: 0x7fe7b3802440
char : 0
Here is the output I EXPECTED:
ptr : 0x7fe7b3802440
heap : 0x7fe7b3802200
offset: 0x000000000240
char : 0x7fe7b3802200
Questions:
1) Why would the char output be zero? (Is this not what I am doing: casting the a pointer in single bytes, and then storing it into an int)
2) If this is not how you properly do the pointer arithmetic, how else would you accomplish the offset?
Edits:
1) Heap is defined as a int*, I think. This is the given piece of code that returns its value.
#define HEAP_SIZE 0x2000
void *my_sbrk(int increment) {
static char *fake_heap = NULL;
static int current_top_of_heap = 0;
void *ret_val;
if(fake_heap == NULL){
if((fake_heap = calloc(HEAP_SIZE, 1)) == NULL) {
return (void*)-1;
}
}
ret_val=current_top_of_heap+fake_heap;
if ((current_top_of_heap + increment > HEAP_SIZE)
|| (current_top_of_heap+increment < 0)) {
errno=ENOMEM;
return (void*)-1;
}
current_top_of_heap += increment;
return ret_val;
}
Pointer arithmetic only makes sense for a specific type. In this example, the int type is size 4 but the pointer subtraction is only 1.
#include <stdio.h>
int array[2];
int *a, *b;
int main(void){
a = &array [0];
b = &array [1];
printf ("Int size = %d\n", sizeof(int));
printf ("Pointer difference = %d\n", b-a);
return 0;
}
Program output:
Int size = 4
Pointer difference = 1
Pointers arithmetic doesn't support the operation (pointer + pointer). The only operation allowed is (Pointer + Integer) so the result is a pointer.
To get the offset you need to cast both pointers to an integer type. And the resulting value is an integer not a pointer.
Example:
int offset = (int)ptr - (int)heap;
printf("ptr : %p\n", ptr);
printf("heap : %p\n", heap);
printf("offset: %d\n", offset);
Also the value of heap is too much large to be stored in a single byte and that's why casting it into a char type returns the value zero.
I want to create a bidimensional array like so:
void **mdeclaraMatrice(int nrLini,int nrColoane, int sizeOfElement)
{
int i;
void **m = malloc(nrLini * 4);
if(m==NULL)
return NULL;
for(i=0; i<nrLini; i++)
{
*(m + (i*4)) = malloc(nrColoane * sizeOfElement);
if(*(m + (i*4)) == NULL)
return NULL;
}
return m;
}
I whant to use it like this:
int **m = (int **)mdeclaraMatrice(n,m,sizeof(int));
but it doesn't work. What do I do wrong?
You should use m[i] instead of *(m+i*4) and let the compiler do the arithmetic.
In addition, you should deallocate the already-allocated memory in case of a failure.
Try this instead:
void **mdeclaraMatrice(int nrLini, int nrColoane, int sizeOfElement)
{
int i;
void **m = malloc(nrLini * sizeof(void*));
if (m == NULL)
return NULL;
for (i=0; i<nrLini; i++)
{
m[i] = malloc(nrColoane * sizeOfElement);
if (m[i] == NULL)
{
while (i-- > 0)
free(m[i]);
free(m);
return NULL;
}
}
return m;
}
[not an answer to the question, but to the indented usage of the proper answer as given by others]
To access the void pointer array as an array of int, doing this
int **m = (int **)mdeclaraMatrice(n,m,sizeof(int));
is not correct, as per the C-Standard only void* converts to any other pointer properly, void** doesn't necessarily. So it shall correctly be
void ** ppv = mdeclaraMatrice(n,m,sizeof(int));
int * pi = *ppv; /* Please note, there is NO casting necessary here! */
Then access the members like so:
pi[0] = 42
pi[1] = 43;
...
Which essently is the same as doing
*((int *) (pi + 0)) = 42;
*((int *) (pi + 1)) = 43;
which indeed does not make sense really as pi already is int*, so the fully correct approach (also taking into account the 2nd dimension) would be:
((int *)(ppv[0]))[0] = 42;
((int *)(ppv[0]))[1] = 43;
Which could be made usable by definging a macro:
#define GENERIC_ARRAY_ELEMENT(type, address, r, c) \
((type *)(address[r]))[c]
GENERIC_ARRAY_ELEMENT(int, ppv, 0, 0) = 42;
GENERIC_ARRAY_ELEMENT(int, ppv, 0, 1) = 43;
I will address the problem of allocation an array of void pointers and then interpreting them as an array of int pointers.
int **nope = (int **)mdeclaraMatrice(n,m,sizeof(int));
Even assuming the allocation was completely correct the assignment and later usage of nope is undefined behavior. void** and int** have incompatible types.
What you can do is the following. Assign the void pointers one by one to an array of int pointers.
void** arrp = mdeclaraMatrice(n,m,sizeof(int));
int* arr[n] ;
for( size_t i = 0 , i < n ; i++ )
arr[i] = arrp[i] ;
And then use the arr array, When you want to free the memory you free the original pointer:
free( arrp ) ;
The problem occurs in this line:
*(m + (i*4)) = malloc(nrColoane * sizeOfElement);
You have to know that when adding a number to an address, the address will be incremented by the number times the size of the object the address points to. So if your pointer points to an object that is of size 4 bytes, and you add 1 to it, then the address will automatically be incremented by 4, not by 1. So you should abandon *4.
Also, use the sizeof operator when allocating space, because addresses (and thus pointers) can have different sizes on different processor architectures.
Actually, you don't even need your generic 2D array function if you know the powerfull VLA features of C99. To allocate a true 2D array (no index array required), you just do this:
int (*twoDIntArray)[width] = malloc(height*sizeof(*twoDIntArray));
That's it. Accesses are just as simple:
twoDIntArray[line][column] = 42;
In this code, twoDIntArray is a pointer to an array of width integers. The malloc() call simply allocates enough space for height such line arrays. When you do the pointer arithmetic twoDIntArray[line], you add the size of line line arrays to the pointer, which produces the address of the corresponding line array. This line array is then indexed by the second array subscript [column].
Needless to say that freeing such an array is just as trivial:
free(twoDIntArray);