Program Won't Do Anything/Compile

I need help with a program that does not compile in Visual Studio. I'm using an online system for C++ that already have its own test cases. However, I always like to do my own program in Visual Studio and run the cases there. So, I been having problem with the code where it doesn't do anything but compiles just fine in the online system. In Visual Studio it generates a "Debug Assertion Failed" error. I have no idea why the program doesn't do anything.
Last edited on
If you're using Visual Studio, why not run it in the debugger?

BTW, the code doesn't make much sense. A description might help, maybe.
For the description, I want to take a file, command line argument and read it. If more than one file are provided then it returns the error from above. Also, I want to be able to return an error if the file cannot be open.

I did the "Start Without Debugging" and that's where I get the "Debug Assertion Failed" error.
Look at lines 6 and 7. How many times does line 7 loop?

I did the "Start Without Debugging"
Why not try to start with debugging? That's how you can tell where it debug assertion failure happens.

Do you understand what a command line argument is? Are you supplying one when you run the program?
Last edited on
If argc is equal to 1 than it won't loop since it starts at 1. I see! Still even if I change it to 0 the program won't do anything.

The command line argument is being supplied automatically by the online IDE system.
Hello joe809,

I think that you may be misunderstanding the command line arguments.

"argv[0]" is always the file name of the program and "argc" is always one to go with "argv[0]".

When VS runs it will set "argv[0]" to the program name and "argc" to one.

Should you have a command line like progName this is a file name.txt "argv[0] is the progName, arg[1] is "this, argv[2] is "is", argv[3] is "a", argv[4] is "file" and srgv[5] is "name.txt". And argc would equal 6.

Should you have a command line like progName "this is a file name.txt". Then argv[0] is the program name and argv[1] is "this is a file name.txt" and argc would equal 2.

In your program on line 6 if "argc" is not equal to one you will by pass the if statement and skip the for loop, which I am having a hard time understanding what it is for.

This may not be what you are looking for, but may give you an idea of how the "arg"s work.
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
#include <iostream>
#include <string>

#include <fstream>

int main(int argc, char* argv[])
{
	std::string str;
	std::ifstream file;

	if (argc > 2)
	{
		std::cout << "\n    To much input!\n";

		//for (int i = 1; i < argc; i++)
		//{
		//	str = argv[i];

		//	file.open(argv[i]);

		//	if (str.find(argv[i]))
		//	{
		//		if (str.find(" ") == std::string::npos)
		//		{
		//			std::cout << "Error, too many files" << std::endl;

		//			return 1;
		//		}
		//	}
		//}
	}

	file.open(argv[1]);

	if (!file)
	{
		std::cout << "\n    File \"" << argv[1] << "\" did not open!\n";

		return 1;
	}
	// <--- Used for testing. Not aactually needed.
	else
		std::cout << "\n    File \"" << argv[1] << "\" successfully opened!\n";

	std::getline(file, str);

	file.close();

	std::cout << "\n " << str << std::endl;

	return 0;
}

BTW do not use "exit()" use return. "exit()" is an unconditional exit from the program and does not allow for things to close properly. Like closing the file or freeing memory created by the string class along with destroying the string object.

On the other hand since you open the file stream with "argv[1]" it really does not matter if there is anything else on the command line unless you want to use it later.

VS does have a way to provide command line arguments to run your program through the IDE. If you do not know how to use this feature I will help you through it.

Andy
Hello Andy,
I need the for loop in order to read the file. The program is more complicated than that and that's why I need the for loop. There are more if statement. The thing is that I'm trying to get the first one working first.

This code below goes inside the for loop and below the first if statement.
1
2
3
4
5
6
7
8
9
10
11
	
/*
This code below takes another input. There are multiple inputs. In this case, this code finds if the input is "x" instead of the file (fstream) and if it contains a "$" in front, it returns as unrecognized.
*/
else if (str.find("x")) {
		x = str.substr(str.find("x") - 1);
		if (x.at(0) != '$') {
			cout << "Not recognized" << endl;
			exit(1);
		}
}
Last edited on
I need the for loop in order to read the file.

Handy Andy is right: you’re probably misunderstanding what ‘argv’ is.
‘argv’ is an array of char pointers, so any elements of the array represent a ‘word’ in the command line. Please re-read what Handy Andy told you.

Breaking the code into functions not only makes it better readable, but helps avoiding logic errors and keep things simple. Example:
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
#include <fstream>
#include <iostream>


bool checkFileName(const std::string& s);


int main(int argc, char* argv[])
{
    if (1 == argc) {
        std::cout << "Usage:\nmain.exe filename\nPlease try again.\n";
        return 0;
    }
    if (2 < argc) {
        std::cout << "Too many arguments in command line.\nExiting now.\n";
        return 0;
    }

    if (!checkFileName(argv[1])) {
        std::cout << "File name is incorrect.\nExiting now.\n";
        return 0;
    }
    
    // Normal program execution
}


bool checkFileName(const std::string& s)
{
    if (s.at(0) == '$') {
        return false;
    }

    // Examples:
    auto last_dot { s.find_last_of(".") };
    if (std::string::npos == last_dot) {    // no name extension
        return false;
    }

    if (s.substr(last_dot + 1, 3) != "txt") {   // extension must be "txt"
        return false;
    }

//    if (bla bla bla) {
//        return false;
//    }

    return true;
}

I want to take a file, command line argument and read it.

If more than one file are provided then it returns the error from above.

Also, I want to be able to return an error if the file cannot be open.

I can't see where you complete step 1. You never attempt to read the file. I'm not sure what you expect to find.

Not sure what you mean by step 2.

If you can't describe what you want to do in words, how can you hope to instruct a computer?
Hello joe809,

Go back and reread my first response then reread what Enoizat said.

kbw wrote:
You never attempt to read the file.

and your response:
What do you mean I never attempted to read the file?
The for loop is doing that?


The one piece of information you have not shown is the command line that you are using. It does not matter what it is, but it does help to know what you are using.

Given your 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
int main(int argc, char* argv[])
{
	string str;
	ifstream file;

	file.open(argv[1]);

	if (argc == 1)
	{
		for (int i = 1; i < argc; i++)
		{
			str = argv[i];

			file.open(argv[i]);

			if (str.find(argv[i]))
			{
				if (str.find(" ") == string::npos)
				{
					cout << "Error, too many files" << endl;

					exit(1); // <--- Use "return" not "exit".
				}
			}
		}
	}

	file.close();

	cout << str << endl;

	return 0;  // <--- Not required, but makes a good break point.
}

Line 6 opens a file stream based on "argv[1]", but then you never check to make sure the file is open and usable.

Line 12 sets "str" equal to "argv[i]" then line 14 tries to open the file using the same file stream that is already open. This does not work. You can not open the same file stream twice.

Lines 16 is checking if "str" contains "argv[i]".

Line - 23 is checking "str" for a space not the file. So as kbw said you are not reading any file just the command line argument.

Now I have the question of why do you need to read the file? There are other ways to determine if the file is empty or contains something.

I am not saying this is the best way, but should give you some ideas of what you can do.
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
#include <iostream>
#include <string>

#include <fstream>

int main(int argc, char* argv[])
{
	std::string str;
	std::streampos begin, end;

	std::ifstream file;

	file.open(argv[1]);

	if (!file)
	{
		std::cout << "\n    File \"" << argv[1] << "\" did not open!\n";

		return 1;
	}

	begin = file.tellg();
	file.seekg(0, std::ios::end);
	end = file.tellg();

	std::cout << "\n The file length of \"" << argv[1] << "\" is: " << end - begin << '\n';

	if (argc > 2)
	{
		for (int i = 2; i < argc; i++) // <--- You have already dealt with "argv[1]".
		{
			//str = argv[i]; // <--- Not used right now.

			std::ifstream test(argv[i]);

			//test.open(argv[i]);

			if (!test)
			{
				std::cout << "\n    File \"" << argv[i] << "\" did not open!\n";

				return i;
			}

			begin = test.tellg();
			test.seekg(0, std::ios::end);
			end = test.tellg();

			std::cout << "\n The file length of \"" << argv[i] << "\" is: " << end - begin << '\n';

			test.close();  // <--- Need to close the file before you use it again.

			//if (str.find(argv[i])) // <--- Looking to find "argv[i]" in the string.
			//{
			//	if (str.find(" ") == string::npos) // <--- Looks for a space in the string not the file.
			//	{
			//		cout << "Error, too many files" << endl;

			//		exit(1); // <--- Use "return" not "exit".
			//	}
		}  //  End for loop.
	}  //  End if statement.

	file.close();

	//std::cout << str << std::endl;

	return 0;  // <--- Not required, but makes a good break point.
}


I put this together to see what the "argv"'s look like.
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
#include <iostream>
#include <string>

#include <fstream>

int main(int argc, char* argv[])
{
	std::string str;
	std::ifstream inFile(argv[1]);
	std::streampos begin, end;
	begin = inFile.tellg();
	inFile.seekg(0, std::ios::end);
	end = inFile.tellg();

	std::cout << end - begin << '\n';

	if (argc > 2)
	{
		std::cout << "\n Given the command line of: (Test.txt File1.txt File2.txt File3.txt File4.txt File5.txt)" << '\n';

		std::cout << "\n argc = " << argc << '\n';

		std::cout << "\n argv[" << 0 << "] is: " << argv[0] << '\n';

		for (size_t lc = 1; lc < argc; lc++)
		{
			std::cout << "\n argv[" << lc << "] is: " << argv[lc];
		}
	}

	// A fair C++ replacement for "system("pause")". Or a way to pause the program.
	// The next line may not be needed. If you have to press enter to see the prompt it is not needed.
	//std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
	std::cout << "\n\n Press Enter to continue: ";
	std::cin.get();

	return 0;	
}


Which produced the output of:


 Given the command line of: (Test.txt File1.txt File2.txt File3.txt File4.txt File5.txt)

 argc = 7

 argv[0] (program name) is: F:\VS 2017\Main V1.exe

 argv[1] is: Test.txt
 argv[2] is: File1.txt
 argv[3] is: File2.txt
 argv[4] is: File3.txt
 argv[5] is: File4.txt
 argv[6] is: File5.txt

 Press Enter to continue:

 
 Given the command line of: (Test.txt File 1.txt File 2.txt File 3.txt File 4.txt File 5.txt)

 argc = 12

 argv[0] (program name) is: F:\VS 2017\Main V1.exe

 argv[1] is: Test.txt
 argv[2] is: File
 argv[3] is: 1.txt
 argv[4] is: File
 argv[5] is: 2.txt
 argv[6] is: File
 argv[7] is: 3.txt
 argv[8] is: File
 argv[9] is: 4.txt
 argv[10] is: File
 argv[11] is: 5.txt

 Press Enter to continue:

 
 Given the command line of: (Test.txt "File 1.txt" "File 2.txt" "File 3.txt" "File 4.txt" "File 5.txt")

 argc = 7

 argv[0] (program name) is: F:\VS 2017\Main V1.exe

 argv[1] is: Test.txt
 argv[2] is: File 1.txt
 argv[3] is: File 2.txt
 argv[4] is: File 3.txt
 argv[5] is: File 4.txt
 argv[6] is: File 5.txt

 Press Enter to continue:



Andy
Topic archived. No new replies allowed.