Как я могу читать аргументы командной строки в любом порядке?
My school assignment is a bank account program that can run in two modes, interactive and bash mode. Right now I'm working on bash mode and need to accept command line arguments to open a database account (just a text file with info for different accounts, like names, account numbers, passwords, and balance) and perform actions like deposit, transfer funds, etc. However, we have to be able to accept these commands in any order the user passes. For instance, if you wanted to deposit something, you would run something like ./bankacct /OTestDB.txt /A12bw3 /Pabc123 /D300.00 where /O opens the database file that stores user info, /A and /P check the account number and password as a way of "signing in", and /D deposits 300 dollars to the account. We've yet to learn classes, and the program is mostly based in using pointers and structures. Additionally, we're only allowed to use c-strings, no string class, but I don't think that has a bearing on this part. So my problem is trying to figure out how to get ./bankacct /OTestDB.txt /A12bw3 /Pabc123 /D300.00 in the same way as ./bankacct /D300.00 /Pabc123 /A12bw3 /OTestDB.txt
Что я уже пробовал:
My first approach to this problem was to set a switch statement that would call the relevant function and just run it through a for loop to cover every argument. But if a user doesn't open the database file first, then I don't have the arguments to pass to a function to "log in" and choose the account. So with my current approach, it seems like the order of command line arguments would need to be constant. So any tips on where to get started would be great, as right now I'm imagining having a set order in which I take arguments and just reading through my argument array with a for loop for each argument until I get to the argument I need. Here's some of my relevant functions:
/* ----------------------------------------------------------------------------- FILE NAME: bankacct_v4.cpp DESCRIPTION: A program that allows manipulation of a bank account database USAGE: ./bankacct_v4 COMPILER: GNU g++ compiler on Linux NOTES: ----------------------------------------------------------------------------- */ #include "bankacct_v4.h" /* ----------------------------------------------------------------------------- FUNCTION: main() DESCRIPTION: controller for the code I guess ADD MORE LATER RETURNS: 0 NOTES: if statement to switch between command line and interactive int argc //number of parameters on command line char *argv[] //an array of pointers to C-strings ------------------------------------------------------------------------------- */ int main(int argc, char * argv[]) { bool flag = true; int num_acct = 0; //This is what you will access with output so you don't print a bajillion blank accounts account* user = new account[100]; if (argc > 1) { for (int i = 0; i < argc; ++i) { cout << "Argument " << i << " : " << left << setw(16) << argv[i] << endl; if (i) commands(argv[i], i); else cout << endl; } } else { cout << endl; } delete[] user; cout << endl; cout << "Programmed by: " << PROGRAMMER_NAME << " -- "; cout << __DATE__ << " " __TIME__ << endl; cout << endl; return 0; } /*----------------------------------------------------------------------------- FUNCTION NAME: void read_file PURPOSE: read in file as designated by command line RETURNS: nothing NOTES: ----------------------------------------------------------------------------- */ void read_file(char* file, account* user, int &num_accts) { ifstream infile(file); if (!infile) cout << "\nError opening file: " << file << "\n\n"; else { cout << "Input file: " << file << endl; while(infile) //won't proceed if end of file WHY DOES THIS WORK { create(user, cout, infile, 0, num_accts); } infile.close(); } } /* ----------------------------------------------------------------------------- FUNCTION: check_arg() DESCRIPTION: checks command line args RETURNS: Nothing NOTES: ----------------------------------------------------------------------------- */ char check_arg(char arg[]) { char buf[100]; const char SLASH = '/'; char valid_options[] = "?ACDFILMNOPRSTW"; char *p = valid_options; bool first_char = arg[0] == SLASH; //Test 1st argument's first character bool second_char = false; for (; *p != 0; ++p) //Test 1st arg's 2nd character { second_char = arg[1] == *p; if (second_char == true) break; } if (!first_char || !second_char) cout << "Invalid argument" << endl; else { cout << "Option: " << *p; if (arg[2] != 0) { strcpy(buf, arg+2); cout << " Value: " << buf; } cout << endl; } return *p; } /* ----------------------------------------------------------------------------- FUNCTION: void create() DESCRIPTION: creates a bank account RETURNS: Nothing NOTES: Use ostream object instead of cout/cin Can I use a loop instead of asking for each individual input? Array of structures ------------------------------------------------------------------------------- */ void create(account* user, ostream &out, istream &in, bool mode, int &num_acct) { if (mode) out << "Last Name? "; in >> user[num_acct].lname; if (mode) out << "\nFirst Name? "; in >> user[num_acct].fname; if (mode) out << "\nMiddle Initial? "; in >> user[num_acct].mi; if (mode) out << "\nSocial Security Number? "; in >> user[num_acct].ssn; if (mode) out << "\nPhone Number? "; in >> user[num_acct].phone; if (mode) out << "\nBalance? "; in >> user[num_acct].bal; if (mode) out << "\nAccount Number? "; in >> user[num_acct].acctnum; if (mode) out << "\nPassword? "; in >> user[num_acct].acctpass; num_acct++; } /* ----------------------------------------------------------------------------- FUNCTION: void display() DESCRIPTION: displays account info RETURNS: Nothing NOTES: Use ostream object instead of cout/cin Does this one really need pass by ref? Copy should be fine. ------------------------------------------------------------------------------- */ void display(account* user, ostream &out, int num_acct) { out << user[num_acct].lname << endl; out << user[num_acct].fname << endl; out << user[num_acct].mi << endl; out << user[num_acct].ssn << endl; out << user[num_acct].phone << endl; out << user[num_acct].bal << endl; out << user[num_acct].acctnum << endl; out << user[num_acct].acctpass << endl; out << endl; } /* ----------------------------------------------------------------------------- FUNCTION: void output() DESCRIPTION: puts array of structures to output file RETURNS: Nothing NOTES: ------------------------------------------------------------------------------- */ void output(account* user, int num_acct) { ofstream outfile; outfile.open("output.txt"); for (int i = 0; i < num_acct; i++) { display(user, outfile, i); } outfile.close(); } /*----------------------------------------------------------------------------- FUNCTION NAME: void commands() PURPOSE: RETURNS: Nothing (void function) NOTES: ?ACDFILMNOPRSTW are valid. stuff ilke /F and /L could probably just be lines like user[i].fname = "value passed". How to take any order? ----------------------------------------------------------------------------- */ void commands(char argv[], int i) { switch (check_arg(argv[i])) { case '?': //helpmenu(); break; case 'A': //readaccountnumber(); ? or set var acctnum to this value? break; case 'C': //createpass(); break; case 'D': //deposit(); break; case 'F': //firstname(); assigns value of first name when creating new account break; case 'I': //output(); for displaying account info break; case 'L': //lastname(); assigns last name break; case 'M': //initial(); assigns middle initial break; case 'N': //phonenum(); assigns phone number break; case 'O': //read_file(char* file, account* user, int &num_accts); reads file info to array of structures break; case 'P': //readpassword(); as a part of "sign in" process break; case 'R': //reportfile(); prints database in form of report file break; case 'S': //ssn(); assigns social security number break; case 'T': //transfer(); (requires two /A and /P) break; case 'W': //withdraw(); break; }
Я также знаю, что не передаю правильные аргументы check_arg, когда вызываю его в командах. Функция работает, если я вызываю ее вместо команд в main, но я не знаю, как check_arg будет знать, что делать на самом деле делать с командами, так как это просто говорит о том, что это были за команды.
PIEBALDconsult
(Не читал ваш код.)
Я не уверен, что буду использовать указатели-скорее всего, простые целочисленные смещения, - но если это требование назначения, то это вряд ли сложнее.
Если вы разрешаете только один из любого конкретного типа аргументов (O, A, P и т. д.), то попробуйте использовать strstr, чтобы найти каждый возможный аргумент и (если таковой имеется) присвоить его адрес указателю на него.
http://www.cplusplus.com/reference/cstring/strstr/
Что-то вроде:
char *argA = strstr ( cmdline , "/A" ) ;
Именно поэтому операционная система никогда не должна пытаться анализировать командную строку и всегда позволять программе делать это самой.
Если вы используете Windows, попробуйте использовать функцию GetCommandLine, чтобы получить фактическую командную строку.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms683156(v=против 85).aspx