I'm trying to implement the following function:
int foo(const void *p, unsigned int n);
Where p is actually a n-levels pointer to an int value and the function must return that value. So:
n = 0: value = (int)(p);
n = 1: value = *(int*)(p);
n = 2: p is a pointer to a pointer to an int value
And so on...
So, I think that the following implementation may be correct:
int foo(const void *p, unsigned int n) {
if (!n) {
return (int)p;
}
return foo((void*)*((int*)p), n - 1);
}
But, in this code, I assume that size of a pointer always equals a size of an int, and I know it is not true. However, since p is always a pointer to pointer to int (n times), I think that maybe I can always cast p to pointer to int as I do in the code.
Is my idea correct? I cannot found any problem similar to this on internet.
Thanks in advance!
Your bottom case of the recursion is not correct, since this supposes that void* and int have the same width.
if (n == 1) return *(int*)p;
Would be better.
this assumes that your int is no bigger than a void*:
int foo(const void *p, unsigned int n) {
if (!n) {
return reinterpret_cast<int>(p);
}
return foo(*static_cast<void**>(p), n - 1);
}
we can avoid that assumption for everything except the n=0 case:
int foo(const void *p, unsigned int n) {
if (!n) {
return reinterpret_cast<int>(p);
}
if (n==1) {
return *static_cast<int*>(p);
}
return foo(*static_cast<void**>(p), n - 1);
}
In C you can replace the static_cast<X> and reinterpret_cast<X> clauses with (X).
I'm not sure what you are trying to accomplish, but I suspect there is a better approach.
Anyway, a pointer to something is the same size as a pointer to a pointer to something, etc.
So you can cast a (void*) to a (void**).
But casting a pointer to an int may loose information, because sizeof(void*) may be > sizeof(int).
You should write:
int foo(const void *p, unsigned int n) {
//if n is 0, then p is already an int, but has been casted to a void*
//This should probably never happend, so you should assert that n > 0
//if n is 1, then p is actually a pointer to an int
if (n == 1) return *(int*)p;
//else dereference it (by casting it to a (void**) and *then* dereferencing it)
return foo(*(void**)p, n-1);
}
In general it's usually better to stick with iterative solution, rather than recursive, if it's possible.
int foo(void *p, unsigned int n) {
for (unsigned int i = 0; i < n; ++i) {
p = *((void**)p);
}
return (int)p;
}
IDEONE: demo
It lets you avoid problems with theoretiaclly possible stack overflow for large ns (I have no idea why would you need to dereference 1000+ levels deep pointer, but I have no idea why you need this function in the first place, so let's keep the function safe) and avoids unnecessary function call overhead (yes, it might get optimized by the compiler, but why not write it optimally in the first place?).
Related
const int* additional(int* s, int* f){
const int* ts = reinterpret_cast<const int*>(*s + *f);
return ts;
}
int main() {
int a = 10, b = 20;
const int* oc = additional(&a, &b);
std::cout << *oc;
return 0;
}
I've tried using static, although it produces the same error
There are many things wrong with your code.
*s + *f is an int, not a pointer (you add the dereferenced values).
you are doing a reinterpret cast which isn't needed at all. Just pass the int's directly without pointers and you are good to go.
const int additional(int s, int f){
return s + f;
}
int main() {
int a = 10, b = 20;
const int oc = additional(a, b);
std::cout << oc;
return 0;
}
You reinterpret the number 30 as a pointer to const int and attempt to read through the reinterpreted pointer. The operating system noticed that the process was attempting to access an address wasn't mapped for the process and sent the segfault signal to terminate the process in order to protect the badly behaving process from itself.
Reinterpret casting is unsafe. Don't use it unless you know what you're doing. And when you know what you're doing, you'll know that it's quite rare to need to use it.
I was aiming to shorten the int t = *f + *s;
That is already extremely short. The function that you defined is much longer and so is even a call to the function. Note that the initialiser expression that you quote has type int while your function returns const int*. That, along with the broken reinterpret cast are the problem.
If you wanted to make the indirection shorter, then how about using references instead of pointers:
const int& f = a;
const int& s = b;
int t = a + b; // shorter
using namespace std;
void* fun(int);
int main()
{
int i;
cin>>i;
int *t = (int *)fun(i);
if(!t)
cout<<"null value\n";
else cout<<*t<<"\n";
return 0;
}
void* fun(int i)
{
if(i==0)
return NULL;
else return (void *)i;
}
Getting segmentation fault on line cout<<*t<<"\n"; (while dereferencing) for all values other than 0
Thanks in Advance!!
void * fun (int i)
This isn't the same i from main, rather a copy of it from a different location solely within the scope of this function fun. Using it outside the function scope through its address will result in undefined behavior. So, pass-by-reference instead and it will take the same i from main
void* fun(int &i)
Second thing is casting an integer to void *. This is converting an integer to address location and dereferencing it causes UB again.
return (void *)&i;
Will return the address can be casted back to int *.
With
return (void *)i;
you return the value of i as a pointer, but that value isn't a pointer in itself and therefore it can't be dereferenced.
You should simply cast it to the correct type, and print it as it is:
cout << reinterpret_cast<intptr_t>(t) << '\n';
//function prototype at the top
void fillRandArray(int A[], int number, int maxNum);
//function declaration
void fillRandArray(int* A, int number, int maxNum) {
for(int i = 0; i < number; i++) {
A[i] = rand() % maxNum + 1;
}
}
int A[MAX_STUDENTS];
fillRandArray(A, number, 44);
I dont understand the code, so the prototype set int A[]
then the declaration set int* A
when we pass the argument, shouldn't we pass like this...
fillRandArray(A[MAX_STUDENTS], number, 44); <---- ???
The code below is passing the name of an array, which is an address.
void fillRandArray(int A[], int number, int maxNum);
The code below this is passing just the name of an address, which happens to be A in this case. They are basically doing the same thing.
void fillRandArray(int* A, int number, int maxNum)
You would not pass the argument like the following:
fillRandArray(A[MAX_STUDENTS],..., ...);
because you told the compiler to expect an address, not an element of the array. So you would just pass it A (i.e. the name of array, which is also the starting address). So it would look like this:
fillRandArray(A, number, 44);
Ask more questions, if I didn't explain it well enough.
The problem is that C-style arrays can't be passed as arguments
to a function. When you write int a[] as a parameter in
a function, the compiler translates it to int* a. In
addition, if you provide a dimension (e.g. int a[10]), it is
simply ignored.
Also, an array can convert to a pointer, and will do so in a lot
of contexts. This is what happens in fillRandArray(A, number,
44); the array A is implicitly converting to a pointer.
As for fillRandArray(a[MAX_STUDENTS], number, 44), this
indexes into the array for the first element; with your
declaration, it passes an int (not an array or a pointer),
except that it accesses one beyond the end of the array, so it's
undefined behavior.
In general, you want to avoid this (although with main, you
can't): the function should either take an std::vector<int>&
a, or in a few special cases, an int (&a)[N] (in which case,
the function should be a template, and N be a template
parameter). So you might write:
template <size_t N>
void fillRandArray( int (&a)[N], int maxNumber )
{
for ( int i = 0; i != N; ++ i ) {
a[i] = rand() % maxNum + 1;
}
}
(But for this sort of thing, std::vector is far preferrable.)
#include <stdlib.h>
int int_sorter( const void *first_arg, const void *second_arg )
{
int first = *(int*)first_arg;
int second = *(int*)second_arg;
if ( first < second )
{
return -1;
}
else if ( first == second )
{
return 0;
}
else
{
return 1;
}
}
In this code, what does this line mean?
int first = *(int*)first_arg;
I thinks it's typecasting. But, from
a pointer to int
to a
pointer to int
little confused here.
Thanks
?
first_arg is declared as a void*, so the code is casting from void* to int*, then it de-references the pointer to get the value pointed from it. That code is equal to this one:
int first = *((int*) first_arg);
and, if it is still not clear:
int *p = (int *) first_arg;
int first = *p;
It is casting a void pointer to a integer pointer and then dereferencing it.
Let's think about it in steps.
void *vptr = first_arg;
int *iptr = (int *)first_arg; // cast void* => int*
int i = *iptr; // dereference int* => int
So, you're specifying the type of data the pointer points to, and then dereferencing it.
int first = *(int*)first_arg;
It's the same as:
int* ptr_to_int = (int*)first_arg;
int first = *ptr_to_int;
That first line does 2 things: it casts the void pointer to an int* and access that memory location to retrieve the value that's there.
There are already many answers to your question, this is more like a comment, something that you will inevitably learn in your quest on mastering C and C++.
Your function is too long. From its name, I predict what you really need is:
int int_sorter( const void *first_arg, const void *second_arg )
{
return *(int*)first_arg - *(int*)second_arg;
}
Is it compulsory to initialize t in the following code, before assigning value to t? Is the code correct?
void swap(int *x, int *y)
{
int *t;
*t = *x;
*x = *y;
*y = *t;
}
You don't need pointer to begin with:
void swap(int *x,int *y)
{
int t; //not a pointer!
t=*x;
*x=*y;
*y=t;
}
int a = 10, b = 20;
swap( &a, &b); //<-----------note : Needed &
--
Or maybe, you want the following swap function:
void swap(int & x,int & y) //parameters are references now!
{
int t; //not a pointer!
t=x;
x=y;
y=t;
}
int a = 10, b = 20;
swap(a,b); //<----------- Note: Not needed & anymore!
is the following section of code correct?
Nopes! Your code invokes Undefined behaviour because you are trying to dereference a wild pointer.
int *t;
*t=*x; // bad
Try this rather
int t; // a pointer is not needed here
t=*x;
or this
int *t = x; // initialize the pointer
That code contains undefined behavior:
int *t;
*t=*x; // where will the value be copied?
Besides that it makes no sense - you need a temporary variable to store the value, not the pointer.
int t; // not a pointer
t=*x;
*x=*y;
*y=t;
It's correct for a pointer.
Only references need to be initialized upon declaration (or in a constructor for instance members).
EDIT: but you got errors in your code, you shouldn't be dereferencing your parameters (ie int *ptr = otherPtr; is fine, not int *ptr = *otherPtr;)
If you just want to make your pointer point to already-initialized data, then you don't need to initialize it. The way you do it, though, yes, you want to use one of the malloc functions to allocate enough heap space for an integer.
The proper, efficient way, to do swapping in C/C++ is
void swap(int *x, int *y) {
int *t = x;
x = y;
y = t;
}
You can find the right way of doing this here
#include <stdio.h>
void swap(int *i, int *j)
{
int t;
t = *i;
*i = *j;
*j = t;
}
Basically the reason has been explained to you by sharptooth but there you will find some more details and explanations about what happens in background when you do such a swap. Hope it helps to clear your ideas.
int *t;
*t=*x;
t is not pointing to any valid location to be able to dereference.
is it compulsory to initialize , before assigning value to pointer t.
Yes, initializing / assigning to point to a valid memory location. Else where would it point to. It might some point to garbage and lead to undefined behavior on dereferencing.