Solved

function member

Posted on 1998-07-29
10
175 Views
Last Modified: 2011-09-20
Hi

I trie to write a program that uses menus.
I want to write a menu class that can be used for every menu that the user wants.
All the class users should do is to declare an object of this class , providing arguments. As the number of arguments is unknown at this time, I thought of declaring a constructor that takes a number of let's say 10 arguments( this will be now the max number of arguments that the object can take) give them implicit values. So when the user provides a number of arguments the rest of them will remain with the initial value( being pointers they just point to null).
I wrote the code and I am posting it now. But I do not like the way I had to write the thing every time for every argument. If I the function was main, I could have the argc argv convention so I could use a loop. This is what I am looking for, a way to avoid writting the code as many times as arguments.

Thank you.

Here is the code:
#include<iostream.h>
#include<string.h>
#include<conio.h>


class CMenu
{
      static float Choice;      
      char *menuItem[9];
public:
        CMenu(char *givenMenuItem1 = NULL, char *givenMenuItem2 = NULL, char *givenMenuItem3 = NULL, char *givenMenuItem4 = NULL, char *givenMenuItem5 = NULL);
        ~CMenu();
        void putMenu();
      void getChoice();
      void returnChoice(float&);
        void returnChoice(int&);
};

float CMenu::Choice;



CMenu::CMenu(char *givenMenuItem1, char *givenMenuItem2, char *givenMenuItem3, char *givenMenuItem4, char *givenMenuItem5)
{
      if(givenMenuItem1 != NULL)
      {
            menuItem[0] = new char[strlen(givenMenuItem1) + 1];
            strcpy(menuItem[0], givenMenuItem1);
      }
      else
            menuItem[0] = NULL;
      if(givenMenuItem2 != NULL)
      {
            menuItem[1] = new char[strlen(givenMenuItem2) + 1];
            strcpy(menuItem[1], givenMenuItem1);
      }
      else
            menuItem[1] = NULL;
   
      if(givenMenuItem3 != NULL)
      {
            menuItem[2] = new char[strlen(givenMenuItem3) + 1];
            strcpy(menuItem[2], givenMenuItem3);
      }
      else
            menuItem[2] = NULL;
      if(givenMenuItem4 != NULL)
      {
            menuItem[3] = new char[strlen(givenMenuItem4) + 1];
            strcpy(menuItem[3], givenMenuItem4);
      }
      else
            menuItem[3] = NULL;
      if(givenMenuItem5 != NULL)
    {
            menuItem[4] = new char[strlen(givenMenuItem5) + 1];
            strcpy(menuItem[4], givenMenuItem5);
      }
      else
            menuItem[4] = NULL;
      cout << "Constructor" << endl;

      
}
      
                  
CMenu::~CMenu()
{
      for(int count = 0; count < 5; count++)
            if(menuItem[count] != NULL)
                  delete menuItem[count];
      
}

void CMenu::putMenu()

{
      cout << "\n\n\t\tEnter your choice" << endl;
      for(int count = 0; count < 10 && menuItem[count] != NULL;count++)
            cout << "\t\t" << count + 1 << "." << menuItem[count] << endl;
      cout << "Press any key to continue" << endl;
}

void CMenu::getChoice()
{
      cout << "getChoice" << endl;
      cin >> Choice;
      cout << "getChoice" << endl;
}

void CMenu::returnChoice(float& passChoice)
{
      passChoice = Choice;
      
}

void CMenu::returnChoice(int& passChoice)
{
      passChoice = (int)Choice;
}

int main()
{
CMenu generalMenu("FIRST", "SECOND");
      
      generalMenu.putMenu();
      generalMenu.getChoice();
      int givenPassChoice;
      generalMenu.returnChoice(givenPassChoice);
      cout << "The choice is = " << givenPassChoice << endl;

      return 0;
}
0
Comment
Question by:simi
  • 8
  • 2
10 Comments
 
LVL 22

Accepted Solution

by:
nietod earned 50 total points
ID: 1168994
answer coming.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1168995
It sounds like you need a "variable argument list" function (that is the official name).  These are functions that are called like printf() where you specify one or more "fixed" parameters followed by any number of "variable" parameters.  These functions are declared by using an ellipsies at the end of the parameter list like.

int SomeFunction(int Fixedparameter, ...)

continues
0
 
LVL 22

Expert Comment

by:nietod
ID: 1168996
When you write a function that takes varialbe argument lists, you need to develop a mechanism that the caller uses to indicate how many variable parameters have been passed (sometimes their type as well.)  For example printf() looks at the string passed in the first parameter and knows that each time it comes to an %XXXX item that there is a cooresponding parameter.  Another approach is to pass an integer count of the number of varaible parameters.  In your case I would pass any number of pointers to strings (menu titles).  With the last one being indicated by a NULL pointer.  Thus you would create a 3 item menu like

CMenu generalMenu("FIRST", "SECOND","THIRD",NULL);

continues.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1168997
To access the variable parameters, you need to use the va_start and va_arg macros.  

Let me know if you have any questions.
0
 

Author Comment

by:simi
ID: 1168998
I think I did not made clear my question.
My problem is not how to pass an undefined ( unlimited) number of parameters to the function. I can handle this by declaring the constructor as receiving a big number of parameters, like 20, becaus I don;t think that someone would like to have too many menuitems in the same menu. I can declare those parameters as pointers and set them to NULL. This way the user can provide two, three or nineteen parameter, the rest will be considered as having default values.
The question is that for every parameter I have to alocate memory for the array variable where I want to store the value, and to copy the value there. I was looking for a way to say like
for(count = 0; count < max_nr_of_arguments && argument[count] != NULL; count++)
{
allocate memory for the array member.
copy the value of the given_parameter[count] in array_member[count]
}

that instead of doing it as many times as passed parameters one by one.

It looks like you are suggesting something when you talk about va_start and va_arg but I have to read about them as I do not know what they mean.

Thanks
0
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
LVL 22

Expert Comment

by:nietod
ID: 1168999
I think the best way to store the information is to use a dynamicaly allocated array of pointers to dynamically allocated strings.  Like

int MenItmCnt = ???;  // set to the number of menu items to store.

char **MenNamTbl = char *[MenItmCnt]; // Allocate array to store pointers to strings.
                                                    // this array would be a member of the class, not a local variable.

for (i = 0; i < MenItmCnt; ++i)
{
    char *ItmNam = ????; // Get pointer to item name parameter to be used.
    MenNamTbl[i] = new char[strlen(ItmNam) + 1] ; // Allocate memory for item name.
    strcpy(MenNamTbl[i],ItmNam); // Copy in item name.
}

the ??? marks are for information you will have to fill in.  You could fill it in using your current approach, but you will find that cumbersome.  I thing you will find the ... approach easier..  But it can be done either way.  

Questions?
0
 
LVL 22

Expert Comment

by:nietod
ID: 1169000
you said
>>what I am looking for, a way to avoid writting the code as many times as arguments

for that you should try a variable argument list and the va_start and va_arg macros.  (You could actually use the macros without the variable argument list, but there is no advantage.  Once you are going to use the macros, you might as well get the other advantages of the variable arguments for free.
0
 

Author Comment

by:simi
ID: 1169001
I read about the va_arg etc.
Here's where I got with the code.
I have problems with the destructor. It works up to this point, but when the first element of the menuItem array is deleted, it gives an error message and it freezes.

I read about the va_arg in my Borland C++ compiler, that it can not be used with char, unsigned char and float. In my Ms Visual C++ compiler it doesn;t say so. Hence, both compilers give examples where the received parameters are integers. Mine are strings. Is that the cause ?

Thanks
#include<iostream.h>
#include<string.h>
#include<conio.h>
#include<stdarg.h>


class CMenu
{
      static float Choice;      
      char **menuItem;
      char *messageBuffer;
public:
        CMenu(char *msg...);
        ~CMenu();
        void putMenu();
      void getChoice();
      void returnChoice(float&);
        void returnChoice(int&);
};

float CMenu::Choice;



CMenu::CMenu(char *msg,...)
{
      
      cout << "Beginning constructor" << endl;
      va_list ap;
      va_start(ap, msg);
      char *arg;
      int count = 0;
      messageBuffer = new char[strlen(msg)];
      strcpy(messageBuffer, msg);
      cout << messageBuffer << endl;
      while (strcmp((arg = va_arg(ap, char* )),"NULL") != 0)
      {
            cout << "Inside while" << endl;
            menuItem[count] = new char[strlen(arg)];
            strcpy(menuItem[count], arg);
            count++;
      }
      menuItem[count] = NULL;
      va_end(ap);
}
                  
CMenu::~CMenu()
{
      cout << "Destructor beginning" << endl;
      for(int count = 0; menuItem[count] != NULL; count++)
      {
            cout << "Inside the for loop" << endl;
            cout << "menuItem[count]=" << menuItem[count] << endl;
            delete [] menuItem[count];
            cout << "Inside the for loop end" << endl;
      }
      cout << "Destructor ends" << endl;
      
}

void CMenu::putMenu()

{
      cout << "\n\n\t\t" << messageBuffer << endl;
      for(int count = 0; menuItem[count] != NULL;count++)
            cout << "\t\t" << count + 1 << "." << menuItem[count] << endl;
      cout << "Press any key to continue" << endl;
}

void CMenu::getChoice()
{
      cout << "getChoice" << endl;
      cin >> Choice;
      cout << "getChoice" << endl;
}

void CMenu::returnChoice(float& passChoice)
{
      passChoice = Choice;
      
}

void CMenu::returnChoice(int& passChoice)
{
      passChoice = (int)Choice;
}

int main()
{
CMenu generalMenu("What do you want to", "pula","pizda", "craci",  "NULL");
      
      generalMenu.putMenu();
      generalMenu.getChoice();
      int givenPassChoice;
      generalMenu.returnChoice(givenPassChoice);
      cout << "The choice is = " << givenPassChoice << endl;

      return 0;
}
0
 
LVL 22

Expert Comment

by:nietod
ID: 1169002
char, and unsigned char can be passed.  The procedure will receive them as ints and unsigned ints. float can be passed as received as double.  This has not effect on you since you are passing pointers.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1169003
in
>> class CMenu
>>     {
>>     static float Choice;      
>>     char **menuItem;
>>     char *messageBuffer;
>>// removed stuff to save space
>>     };

you probably don't need messageBuffer.  That is used only in one function, so declare it in that function.  The class should only store data that is preserved between functions.

The dynamically allocated string pointer array

>> char **menuItem;

is never allocated.  you use this arrray (pointer to an array) without creating it.

>>messageBuffer = new char[strlen(msg)];
>>   strcpy(messageBuffer, msg);

you need to allocate "strlen(msg) + 1" characters to have room for the NUL terminator.at the end of the string.  
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Suggested Solutions

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now