Home > database >  In C is there an optimal way to run down a pointer chain to the value?
In C is there an optimal way to run down a pointer chain to the value?

Time:09-16

Lets say I have a program and a value like int finalValue = 1234;. Next there are pointers that point to finalValue. For Example:

int *p = &finalValue;
int **p2p = &p;
int ***p2p2p = &p2p;

If I wanted to create a function that ran down the pointer chain till it got to the finalValue (1234) what would be the most optimal way of doing it if the number of pointers too pointers can change.

The function would be given the first pointer in the chain (so in the above case p2p2p). General traversal would look like p2p2p -> p2p -> p -> finalvalue.

How do I do this for an unknown number of pointer in a chain (min 1, max of 5)

Initial prototyping brought me to using

foo(pointer) {
    while (typeid(pointer).name() != "int") {
        //do traversal through pointer chain
    }
    return pointer; //at this point it would have the value 1234
}

But I dont know how to properly traverse down the chain, or how to efficiently check and stop.

Any help is appreciated.

CodePudding user response:

If you have c 17, you can use a recursive function like so:

template<typename T>
constexpr auto get_pointer_value(T v) {
    if constexpr (std::is_pointer_v<T>) {
        if (!v) { // Optional error handling if you can't trust the caller.
           throw std::invalid_argument("Pointer v cannot be null");
        }
        return get_pointer_value(*v);
    } else {
        return v;
    }
}

Live example.

The intent is nice and clear and this should all be sorted out at compile time.


If you do trust the user, it might be worth adding an assert(v) to the pointer section of the constexpr if anyway.

CodePudding user response:

You can create 2 "versions" of foo(). One that operates on object references, and one that operates on pointers (including pointers to pointers). With the later calling foo() recursively after dereferencing its argument.

The compiler will chain things appropriately:

template<typename T>
T& completely_dereference(T& v) { return v; }

template<typename T>
auto& completely_dereference(T* ptr) { return completely_dereference(*ptr); }

CodePudding user response:

The simplest way is probably using template specialization. We'll want to make two versions of a function, one that takes a T and one that takes a T*.

template <typename T>
auto reduce(T pv) {
    return pv;
}

template <typename T>
auto reduce(T * pv) {
    return reduce(*pv);
}

int main() {
    int v = 10;
    auto s = &v;
    auto ss = &s;
    auto sss = &ss;

    std::cout << reduce(v) << ' ' << reduce(s) << ' '
              << reduce(ss) << ' ' << reduce(sss) << '\n';
    return 0;
}

When calling reduce with a non-pointer type, it will bind to the first version which just becomes an identity function. When calling with a pointer type, it'll bind to the second version, which calls reduce on the de-referenced value.

Output from above:

10 10 10 10
  • Related