While Loop Fails?

I'm wondering why my program crashes at my while loop when run with a file containing "print hello world". Here's the code including the if statement:

1
2
3
4
5
6
7
8
9
if (tokens[0] == "print") {
                        e = sizeof(tokens) / sizeof(tokens[0]);
                        e--;
                        f = 1;
                        while (f <= e) {
                            cout << tokens[f];
                            f++;
                        }
                    }
what type tokens is? Is it array of std::string?
Last edited on
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.
tokens is a string array. It contains a few strings: print hello world.
Is tokens a dynamic array?
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?
Last edited on
Here's the full code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <iostream>
#include <string>
#include <windows.h>
#include <fstream>
#include <vector>
#include <sstream>

using namespace std;

void SetColor(unsigned short 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;

        unsigned int a; // first for loop var.
        unsigned int b = 0; //
        unsigned int c = 0; // Spaces in the string to parse
        unsigned int d = 0; // Number of tokens in string array
        unsigned int 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
                        }
                    } else if (tokens[0] == "pause") {
                        getchar();
                    } else if (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.

Are you using MSVS?
Last edited on
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?
Last edited on
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 = new int[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.
Last edited on
Is it possible to tokenize and parse a string vector?
Something like this:
1
2
3
4
5
6
            vector<string> tokens;
            stringstream ss(line);
            while (ss >> token)      // add tokens to array
            {
                tokens.push_back(token);
            }


1
2
3
4
5
6
7
            else if (tokens[0] == "print")
            {
                for (int e=1; e < tokens.size(); e++ )
                {
                    cout << tokens[e] << " ";
                }
            }
Dang, I didn't know vectors were that cool :)

Thanks dude, you've shown me how to use a vector right, and have shown me how to print words from a file. You're good at this, aren't you?
Thanks. I have good days and bad days. But I try.
Topic archived. No new replies allowed.