Reputation: 37
I'm fairly new to C++ and just learning it on my own, so please go somewhat easy on me. What I am trying to do:
The code I wrote functions as I want it to, yet the errors and warnings in the build terminal indicate that something is not correct. I have tried using different data types but I have run out of ideas. By using a char * array for the program names I got it down to one warning: "ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]". I would love to get some clarity on what I am doing wrong that causes this warning.
This is the code:
#include <stdio.h>
#include <conio.h>
#include <iostream>
#include <string.h>
#include <windows.h>
using namespace std;
void keyControl(), randomNumber();
// What data type for array?
string programList[99] = {"keyControl", "randomNumber"};
char writeWord[18] = "";
int main(){
// Is there an equivalent of strcmp() for string datatype?
while(strcmp(writeWord, "quit") != 0){
system("@cls");
cout << ("\n\tProgram list:\n\t");
for(int x = 0; x < 99; x++){cout << (programList[x]) << (", ");}
cout << ("\n\n\tType a program to run or 'quit' to exit:\n\n<");
// Is there an equivalent of gets() for string datatype?
gets(writeWord);
system("@cls");
if(strcmp(writeWord, programList[1]) == 0){
//keyControl();
}
if(strcmp(writeWord, programList[2]) == 0){
//randomNumber();
}
}
return 0;
}
And yes, I have read everywhere that gets() is a no-no but this is only a quickly thrown together test program and I would use something else if I was actually writing code seriously or for work, etc. I'm only doing this for fun and learning purposes currently, and want to focus on one thing at a time :-)
Thanks
Upvotes: 0
Views: 351
Reputation: 84541
Fast forward a couple of decades in C++ and find the STL container std::map which maintains a unique set of key/value pairs. In your case you want to associate (map) and string with a function pointer so that when "keyControl"
is entered by the user, the keyControl()
function is called, and so on.
In your case you can populate a std::map
with your key/values pairs by creating a map that associates a std::string
and void(*)(void)
pointer as a pair, e.g.
/* std::map with string as key and function pointer as value */
std::map<std::string, void(*)(void)> proglist {{"keyControl", keyControl},
{"randomNumber", randomNumber}};
Then it is simply a matter of looping continually, prompting the user for input and checking if the input matches one of the keys in the std::map
, if it does, you executed the mapped function.
getline()
is used for input into a std::string
(read again the page on why gets()
should NEVER be used). C++ provides an overload of ==
for comparing string equality. You can set various exit conditions based on the stream-state after your call to getline()
or based on the content of the input filled. For example:
std::string line {}; /* line for input */
while (1) { /* loop continually */
std::cout << "\nenter program name: "; /* prompt for input */
/* read line, break on manual EOF, empty input or "quit" */
if (!getline (std::cin, line) || line.length() == 0 || line == "quit")
break;
If the user generates a manual EOF
(Ctrl + d Linux or Ctrl + z windows), if the string is empty (e.g. the user simply pressed Enter) or the string read is "quit"
-- adjust to meet your needs.
All you need to do to check if the input matches a key in your std::map
is to use the .find()
member function that will return a pointer to the mapped pair if found or will return the end of the std::map
if not found. The value part of the key/value pairt held in the map is accessed through the member name second
(key is first
, value is second
) So you can do:
/* read line, break on manual EOF, empty input or "quit" */
if (!getline (std::cin, line) || line.length() == 0 || line == "quit")
break;
auto found = proglist.find (line); /* search for input in map */
if (found == proglist.end()) { /* if not found, show error */
std::cerr << " error: no matching program name.\n";
continue;
}
found->second(); /* otherwise execute the function */
Putting it altogether, you would have:
#include <iostream>
#include <string>
#include <map>
void keyControl()
{
std::cout << "keyControl() called.\n";
}
void randomNumber()
{
std::cout << "randumNumber() called.\n";
}
int main() {
/* std::map with string as key and function pointer as value */
std::map<std::string, void(*)(void)> proglist {{"keyControl", keyControl},
{"randomNumber", randomNumber}};
std::string line {}; /* line for input */
while (1) { /* loop continually */
std::cout << "\nenter program name: "; /* prompt for input */
/* read line, break on manual EOF, empty input or "quit" */
if (!getline (std::cin, line) || line.length() == 0 || line == "quit")
break;
auto found = proglist.find (line); /* search for input in map */
if (found == proglist.end()) { /* if not found, show error */
std::cerr << " error: no matching program name.\n";
continue;
}
found->second(); /* otherwise execute the function */
}
}
Example Use/Output
$ ./bin/map_str_fn
enter program name: foo
error: no matching program name.
enter program name: keyControl
keyControl() called.
enter program name: randomNumber
randumNumber() called.
enter program name: quit
Getting familiar with the STL containers will save you no end of grief using C++. The library has more than a decade and a half of validation and efficiency tweaks and will be far more robust than whatever you "whip-up" on the fly.
Look things over and let me know if you have questions.
Upvotes: 1