Thread: Dynamic array of function pointers

  1. #1
    Registered User
    Join Date
    Dec 2009
    Posts
    47

    Dynamic array of function pointers

    Below is what I want to accomplish. These function pointers depend on how many functions I will be creating. They will always follow the pattern function1, function2, etc.. where it will be function#. Is there any way to go through a loop that assigns function# up to n to these array values? So my code snippet will always populate the array of function pointers up to n with function#'s? Or do I have to hard code an array with functions1...n, than only use the indices 0 to n? Hopes this makes sense, thanks.

    Code:
    typedef void (*FuncPtr)();
    FuncPtr* funcPtrs = new FuncPtr[ # ];
    
    //where N is variable
    for(i=0;i<N;i++)
    {
      funcPtrs[i] = &functionN
    }

  2. #2
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    You could do it with macro magic, but why would you want to? By necessity you will have N functions, therefore you can make just a regular array of them. You could just use the initializer and not have to write a loop at all.

  3. #3
    Registered User
    Join Date
    Dec 2009
    Posts
    47
    What's macro magic? This isn't a one time solution, when we recompile under different circumstances we may have 4 functions today, 8 tomorrow, 3 the next day etc..It's the nature of the program, each function represents a distinct subroutine needed for a seperate area we are generating. So I want to be able to say, this time we have 4, give me an array that's the size of the day with pointers to all the functions of the day (following a consistent pattern of function0...functionN). Is there some variable way I can do this with macros?

    All i really got so far is a switch statement, populating my array up to N times depending on the case. So as of now its limited up to 10 functions (i figured that was a high enough max for now). But it's not a variable/dynamic solution really which I was hoping for. In perl for example you can easily say things like function$variable (where $variable is 0..N), but I guess there's nothing like that in C++.

    But also the problem with prototyping these variable functions, this becomes quite difficult without a bunch of conditional preprocessor branches and a single define stating how many functions I will have....
    Last edited by tempster09; 08-11-2010 at 08:44 PM.

  4. #4
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Well I still don't see a reason to avoid a normal array. The preprocessor can help you compile sections of code. I'll show a contrived example in a moment. Before that though, I assumed you would write a maximum number of functions.

    So it depends on what you will link. As far as what gets compiled:

    Code:
    #define MAX_FUNCS 6
    #define MIN_ARRAY 3
    
    FuncPtrs doThis[MAX_FUNCS] = {
    #if COMPILE_FUNCS == MIN_ARRAY
       &foo, 
       &bar,
       &baz,
    #elsif COMPILE_FUNCS == 4
       &foo,
       &bar,
       &baz,
       &quz,
    #else /* case COMPILE_ALL */
       &foo,
       &bar,
       &baz,
       &quz,
       &qux,
    #endif
    };
    This way, you can define a macro COMPILE_FUNCS with some implementation dependent, special number that will keep what you are using and ignore the other compiling options. COMPILE_FUNCS is the length of the array. As long as there is a MIN_ARRAY you will always use this technique can work.

    You get the best of everything: array initializers, automatic storage, and case specific compiling.

    You'll want to do this after committing more research time to the C++ preprocessor. Things can be a lot more robust then what I've shown you, such as making the compiler throw an error if there is a logical problem or a needed define is missing. But this is what I recommend.

  5. #5
    Anti-Poster
    Join Date
    Feb 2002
    Posts
    1,401
    Or you could use Boost and some template metaprogramming:
    Code:
    #include <iostream>
    #include <boost/mpl/vector.hpp>
    #include <boost/mpl/push_back.hpp>
    #include <boost/mpl/at.hpp>
    #include <boost/mpl/size.hpp>
    #include <boost/mpl/for_each.hpp>
    
    template <int I>
    struct Function;
    
    template <>
    struct Function<0>
    {
       static void func()
       {
          std::cout << "In Function 0" << std::endl;
       }
    };
    
    template <>
    struct Function<1>
    {
       static void func()
       {
          std::cout << "In Function 1" << std::endl;
       }
    };
    
    // Define more functions here if desired
    
    template <int I>
    struct FunctionArray_;
    
    template <int I>
    struct FunctionArray_
    {
          typedef typename boost::mpl::push_back<
             typename FunctionArray_<I - 1>::type, Function<I - 1>
          >::type type;
    };
    
    template <>
    struct FunctionArray_<0>
    {
       typedef boost::mpl::vector<> type;
    };
    
    // Modifying this will include that many functions
    const int NUMBER_OF_FUNCTIONS = 2;
    
    typedef FunctionArray_<NUMBER_OF_FUNCTIONS>::type FunctionArray;
    typedef void (*FuncPtr)();
    
    struct FunctionPointerAssigner
    {
    private:
       int index_;
       FuncPtr* funcArray_;
    public:
       FunctionPointerAssigner(FuncPtr* funcArray) : index_(0), funcArray_(funcArray) { }
    
       template <class T>
       void operator()(T)
       {
          funcArray_[index_] = &T::func;
          index_++;
       }
    };
    
    int main()
    {
       std::cout << "Compile time calls" << std::endl;
       boost::mpl::at_c<FunctionArray,0>::type::func();
       boost::mpl::at_c<FunctionArray,1>::type::func();
    	
       std::cout << "Runtime calls through function pointers" << std::endl;
       FuncPtr funcPtrs[boost::mpl::size<FunctionArray>::value];
       boost::mpl::for_each<FunctionArray>(FunctionPointerAssigner(funcPtrs));
       for(int i = 0; i < NUMBER_OF_FUNCTIONS; i++)
          funcPtrs[i]();
    
       return 0;
    }
    Output:
    Code:
    Compile time calls
    In Function 0
    In Function 1
    Runtime calls through function pointers
    In Function 0
    In Function 1
    If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein

  6. #6
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    If you know the number of functions
    Code:
    #define FUNC_NUMBER 100
    #define FUNCTION(i) function##i
    
    typedef void (*FuncPtr)();
    FuncPtr* funcPtrs = new FuncPtr[FUNC_NUMBER];
    
    for(i=0;i<FUNC_NUMBER;i++)
    {
      funcPtrs[i] = &FUNCTION(i);
    }
    The ## concats the two strings so you would have function1, function2, etc etc

  7. #7
    Anti-Poster
    Join Date
    Feb 2002
    Posts
    1,401
    Hmm, won't that for loop just get the address of functioni() FUNC_NUMBER times? The macro is handled at compile-time; the for-loop isn't evaluated until run-time.
    If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    No, "##i" should be replaced with the contents of i.
    But them main problem I have with the code (except that it's runtime, of course), is that it's using raw pointers, new and no delete.
    Replace it with a vector, use push_back and you're done.

    EDIT: Oops. Turns out that's not right. See below.
    Last edited by Elysia; 08-12-2010 at 01:07 PM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Elysia
    No, "##i" should be replaced with the contents of i.
    pianorain's reasoning sounds correct, and a quick test confirms it. Perhaps the use of the identifier i is confusing; if we change the macro to:
    Code:
    #define FUNCTION(x) function##x
    then it will still be the case that "that for loop (will) just get the address of functioni() FUNC_NUMBER times". Consequently, C_ntua's idea does not work.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Ah, now I see. I didn't read that correctly.
    Of course. "i" is passed, so obviously that would be what is pasted.
    My bad.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    Registered User
    Join Date
    Dec 2009
    Posts
    47
    Thanks, I didn't really think it was possible to do something like that in C but I forgot I have done things like your macro in the past. That's exactly what I was looking for. These functions will be stored in seperate .cpp files each because they will be rather large, so what's the best way to go about calling them from let's say main.cpp? Should I just prototype function1...functionN to a reasonable maximum that I should not pass like 50...? Or include function1...functionN header files (will that work if they don't exist?)...Again I guess i'm asking for a variable way to do this or way to access these functions without having to do work every time I add or remove one. Thanks

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    One way is to put them in header files and mark them inline. That way you don't need prototypes.
    Another way is to abuse templates since you really don't need prototypes there, either. And with templates, you can give your functions all the same name but with a unique identifier (integer) like pianorain showed.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #13
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Quote Originally Posted by tempster09 View Post
    Thanks, I didn't really think it was possible to do something like that in C but I forgot I have done things like your macro in the past. That's exactly what I was looking for. These functions will be stored in seperate .cpp files each because they will be rather large, so what's the best way to go about calling them from let's say main.cpp? Should I just prototype function1...functionN to a reasonable maximum that I should not pass like 50...? Or include function1...functionN header files (will that work if they don't exist?)...Again I guess i'm asking for a variable way to do this or way to access these functions without having to do work every time I add or remove one. Thanks
    I guess you're asking about the method I showed. Um, it's hard for me to answer all of your questions. Bear with me.

    Building a C++ project effectively goes through two stages. First is the compile stage. To minimize work here, you could use an implementation dependent compiler switch to define the macro that controls the case logic. Unless you have to change the case logic, then you can compile without changing the source.

    Compiling produces object code. This is NOT AT ALL related to the OOP object concept. They are a part of the final result (an executable). Object code or object files are the input to the linker, in the second stage.

    You have to make sure you have all the functions in you're using in object code, and then make an executable or you will get linker errors. However that is easiest for you is the way you should organize the source.

    The way to get a clean build depends. If you have to manage your object code by hand, I pity you. You may be able to define custom build targets in a custom makefile and not have to edit project details at all. I am not privy to your software choices or how their makefiles -- or whatever vendor foo calls them -- work. Optionally, your IDE should let you remove but not delete function implementations that you are not using from the project and just rebuild. The good news is you can also #include conditionally, using similar case logic to what I've shown you, to prevent editing the source.

    It sounds a lot harder than a MPL solution, but I have a feeling people here are making MPL sound deceptively easy as well. We're not really functioning with the clearest picture of your plans.

    That's all I have to say.

    EDIT: Oh! And additionally, inline does almost nothing you can depend on. If that is a part of your solution don't expect it to inline %100 of the time.
    Last edited by whiteflags; 08-12-2010 at 05:20 PM.

  14. #14
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Well, you could always use a scripting language or even C++ to read source file and run that program/script prior to compiling. It would be reasonable since you have a distinct name for the functions as "functionN".

    The template solution is clever and probably the more real solution, but practically it is not worth the trouble and the "less readable" effect it will give.

  15. #15
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Less readable is subjective and I wouldn't say it's trouble at all.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Compiling C in Visual Studio 2005
    By emanresu in forum C Programming
    Replies: 3
    Last Post: 11-16-2009, 04:25 AM
  2. In over my head
    By Shelnutt2 in forum C Programming
    Replies: 1
    Last Post: 07-08-2008, 06:54 PM
  3. two-dimensional dynamic array of pointers to classes
    By Timo002 in forum C++ Programming
    Replies: 4
    Last Post: 04-21-2005, 06:18 AM
  4. Unknown Memory Leak in Init() Function
    By CodeHacker in forum Windows Programming
    Replies: 3
    Last Post: 07-09-2004, 09:54 AM
  5. qt help
    By Unregistered in forum Linux Programming
    Replies: 1
    Last Post: 04-20-2002, 09:51 AM