If tokens is a string, how can you possibly compare a single character in that string to the string "print"? It's not like by making the statement if(tokens[0] == "print") the program will parse through every character until it finds "p", immediately check the next one for "i" and so on. That, and you are setting e to be the size of the string divided by the size of a character, which is also invalid. One small tidbit as well- you could easily replace that while statement with a for statement, for simplicity.
program crashes at my while loop when run with a file containing "print hello world"
The mention of a file suggests the input to the program comes from an external file, where the size of the data cannot be known at compile-time.
Consequently, this sort of calculation sizeof(tokens) / sizeof(tokens[0]) based upon what is known at compile time, cannot give any useful result.
Either maintain a separate field which contains a count of how many elements of the array are in use, or more simply, use a vector which can keep track of its own size during use.
lmsmi1 wrote:
tokens is a string array. It contains a few strings: print hello world.
But what sort of string? A C++ std::string, or a plain null-terminated c-string?
#include <iostream>
#include <string>
#include <windows.h>
#include <fstream>
#include <vector>
#include <sstream>
usingnamespace std;
void SetColor(unsignedshort color) {
HANDLE hcon = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hcon, color);
}
BOOL WINAPI SetConsoleIcon(HICON hIcon) {
typedef BOOL (WINAPI *PSetConsoleIcon)(HICON);
static PSetConsoleIcon pSetConsoleIcon = NULL;
if(pSetConsoleIcon == NULL)
pSetConsoleIcon = (PSetConsoleIcon)GetProcAddress(GetModuleHandle(("kernel32")), "SetConsoleIcon");
if(pSetConsoleIcon == NULL)
return FALSE;
return pSetConsoleIcon(hIcon);
}
int main(int argc, char* argv[])
{
SetConsoleTitle("OpenCMD v1.0.0");
HICON hIcon = LoadIcon(GetModuleHandle(0),"MAINICON");
SetConsoleIcon(hIcon);
if (argc<2) {
cerr << "OpenCMD v1.0.0\n(C) Copyright 2013 HackForums";
getchar();
return(0);
} else {
string line;
string cmd;
string params;
string token;
unsignedint a; // first for loop var.
unsignedint b = 0; //
unsignedint c = 0; // Spaces in the string to parse
unsignedint d = 0; // Number of tokens in string array
unsignedint e = 0; // Extra interger to use with parsing commands from file (Ex. print ...)
// unsigned int f = 0; // Spare int
ifstream file;
file.open(argv[1]); // Args start a 0, then go up by 1. argv[0] is the Program path.
if(!file.is_open()) {
file.close();
cout << "Error opening file.";
} else {
while(!file.eof()) { // While the file isn't ended
b = 0;
c = 0;
d = 0;
getline(file, line); // get the command's whole line
if (!line.empty()) { // If the line isn't empty...
for (a = 0; a < line.length(); a++) { // Tranform string to lowercase
tolower(line.at(a));
}
while(isspace(line.at(b))) {
b++;
for(; b < line.length(); b++) {
if(isspace(line.at(b))) {
c++;
// Skip over duplicate spaces & if a NULL character is found, we're at the end of the string
while(isspace(line.at(b++))) {
if(line.at(b) == '\0') {
c--;
}
}
}
}
}
c++;
string tokens[c]; // initialize the number of tokens to number of spaces + 1
stringstream ss(line);
while (getline(ss, token, ' ')) { // add tokens to array
tokens[d] = token;
d++;
}
if (tokens[0] == "color") { // check first token (0)
if (tokens[1] == "-green") { // check second token (1)
SetColor(10); // do command for the tokenized string read
}
} elseif (tokens[0] == "pause") {
getchar();
} elseif (tokens[0] == "print") {
e = 1;
while (e < (sizeof(tokens) / sizeof(tokens[0]))) {
cout << tokens[e];
e++;
}
} else {
cout << "OpenCMD has read an unknown command: " << tokens[0];
getchar();
}
}
}
file.close(); // Close File
}
}
return(0);
}
tokens is a C++ string, and I don't know why the while loop won't print whatever is after "print" to the console.
string tokens[c];
Variable Length Arrays are not supported in C++
It should give you a warning. If it doesn't — turn on warnings.
Looks all problem arises from use of VLA and sizeof together, which is undefined behavior actually.
No. I'm using codeblocks 12.11 (as an IDE. Mingw is my compiler). If I can't define the number of elements in an array via an int variable, how do I set the number of elements in tokens to the number of words in the string that was tokenized?
Oh, yes, gcc partially supports VLA. I usually compile with -pedantic-errors so it isn't used.
a) You can dynamically allocate your array:
1 2
int* x = newint[c];
x[2] = //....
However you will need to save your c variable because it holds your array size which you cannot deduce.
And you need to delete array when you done with it: delete[] x;
b) You can use one of standard collections: std::vector<std::string> will do it for you.
It has a size() member function, support insertion, deletion and other manipulations with it.