Trouble when using functions?

I created this program without functions and it worked fine... can anyone help me figure out why when I split the code into functions the totals that print are all zero? I was getting the correct totals before the functions.

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
// Unit 10 modularized.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include<iostream>
#include<string>
#include<fstream>
using namespace std;

// Declare functions
void openFile();
void printFile(fstream &);
int countChars(fstream &, int& upper, int& lower, int& digit);
void printCount(fstream &, int upper, int lower, int digit);

// Declare file stream object
fstream file;

// Declare global variables
char ch;
int upper;
int lower;
int digit;


int main()
{
	openFile();
	printFile(file);
	countChars(file, upper, lower, digit);

	// print spaces for clean look
	cout << "\n";
	cout << "\n";

	// system pause and screen clear
	system("pause");
	system("CLS");

	printCount(file, upper, lower, digit);

    return 0;
}

void openFile()
{
	file.open("text.txt", ios::in); // opens file
}

void printFile(fstream &file)
{
	if (file) // makes sure file was opened successfully
		while (file)
		{
			file.get(ch);
			cout << ch;
		}
	else
		cout << "Error handling file!\n"; // file error check
}

int countChars(fstream& file, int& upper, int& lower, int& digit)
{
	if (file)
		while (file >> ch)
		{

			file.seekg(0);
			file.get(ch);
			
			if (ch >= 'A' and ch <= 'Z')
			{
				upper += 1;
			}
			else if (ch >= 'a' and ch <= 'z')
			{
				lower += 1;
			}
			else if (ch >= '0' and ch <= '9')
			{
				digit += 1;
			}
		}
	return upper, lower, digit;
}

void printCount(fstream &file, int upper, int lower, int digit)
{
	cout << "The total number of uppercase letters: " << upper << endl;
	cout << "The total number of lowercase letters: " << lower << endl;
	cout << "The total number of digits: " << digit << endl;
}





You call countChars on line 30, but at this point upper, lower, and digit are still uninitialized. Inside of countChars, you then increment these values. junk += 1 still produces junk!

When you call printFile, you exhaust your file stream until file becomes in a bad state (the file finishes). But then in countChars, you immediately check if (file). This will surely fail because you already exhausted your file stream.

1
2
3
4
5
		while (file >> ch)
		{

			file.seekg(0);
			file.get(ch);

You're constantly resetting file's file position...? Isn't this an infinite loop for you?

Also, what are you expecting line 84 to do? A function can only return 1 object.
https://en.wikipedia.org/wiki/Comma_operator
So I moved the seekg to before the loop and I am still getting 0 for my totals. What else do I need to do?
Take it one step at a time. Don't just look at the final thing and be like "it's wrong, what do I do".

Figure out where in your program it first starts to deviate from what you expect it to do.
Give it a short file, with like 2 words in it, and go through your logic, line by line, to figure out exactly what and where something is going wrong. I strongly suggest using a debugger, but if you're stubborn, try adding more print statements to see what's happening at each part of your program.

If your total is not being updated, that means your upper/lower/digits are not being incremented. Why would that be?

Note that my_stream.clear() resets the error state of a I/O stream.
Last edited on
I feel like it's because the file isn't resetting properly before the increment lines begin, but I added the file.seekg(0) before I start it and it didn't fix it... I also know that if I remove printFile() from main my totals work fine. So to me that shows that after printFile runs, the file is not being properly read in the totals function. I am just confused on how to resolve it...
If your file isn't being reset properly, try file.clear() to reset the error state of a I/O stream. Or, you could re-assign it, ex: file = std::fstream("text.txt", ios::in);
Last edited on
I changed the seekg line to file.clear() and I am still seeing no changes... what else could be causing the file to not reset? Am I passing fstream into the function properly? I am passing it by reference... is that correct? Are there any changes needed in the structure of the function?
closed account (SECMoG1T)
hello @stormbot, well @Ganado already gave you the solution but maybe you missed it.

by the time you are calling your count char, the stream is in a bad state because the "EOF"
bit is set, i notice that you did not checking if your stream was in a bad state and that would have saved you some time.

i have attempted to correct your code and give you some pointers using comments, hope you get the point.

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
#include<iostream>
#include<string>
#include<fstream>
using namespace std;

// Declare functions
void openFile();
void printFile(fstream &);
int countChars(fstream &, int& upper, int& lower, int& digit);
void printCount(fstream &, int upper, int lower, int digit);

// Declare file stream object
fstream file;

// Declare global variables
char ch;
int upper;
int lower;
int digit;


int main()
{
	openFile();
	printFile(file);
	countChars(file, upper, lower, digit);

	// print spaces for clean look
	cout << "\n";
	cout << "\n";

	// system pause and screen clear
	system("pause");
	system("CLS");

	printCount(file, upper, lower, digit);

    return 0;
}

void openFile()
{
	file.open("test.txt", ios::in); // opens file
}

void printFile(fstream &file)
{
	if (file) // makes sure file was opened successfully
		while (file)
		{
			file.get(ch);
			cout << ch;
		}
	else
		cout << "Error handling file!\n"; // file error check
}

int countChars(fstream& file, int& upper, int& lower, int& digit)
{
    ///your file eof is already set you need to reset your file stream before use
    file.clear(); ///clear
    file.seekg(0); ///reset read pos

	if (file)
		while (file >> ch)
		{

			///file.seekg(0); remove from here
			///file.get(ch);  consumes an extra character

			if (ch >= 'A' and ch <= 'Z')
			{
				upper += 1;
			}
			else if (ch >= 'a' and ch <= 'z')
			{
				lower += 1;
			}
			else if (ch >= '0' and ch <= '9')
			{
				digit += 1;
			}
		}

    else
        std::cout<<"\nbad stream\n"; ///check if your stream failed

	return upper, lower, digit; ///this return is wrong, make this a void function your are passing you vars by ref.
}

void printCount(fstream &file, int upper, int lower, int digit) ///file is unused am sure you don't need it
{
	cout << "The total number of uppercase letters: " << upper << endl;
	cout << "The total number of lowercase letters: " << lower << endl;
	cout << "The total number of digits: " << digit << endl;
}



IMPORTANT: if your file isn't really big , please load it into an array or an stl container and work on the data from there, dealing with direct file streams can be resource consuming and error prone.
How do I handle the file.get line consuming an extra character?
closed account (SECMoG1T)
first of all note that file.get(ch) and file>>ch achieves the same functionality, so you only need one of the two to handle the read.

How do I handle the file.get line consuming an extra character?

delete that line from the code, your program will work fine.

this two approaches does the same thing

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
void countChars(fstream& file, int& upper, int& lower, int& digit)
{
    file.clear(); 
    file.seekg(0);

	if (file)
		while (file >> ch)
		{
			if (ch >= 'A' and ch <= 'Z')
			{
				upper += 1;
			}
			else if (ch >= 'a' and ch <= 'z')
			{
				lower += 1;
			}
			else if (ch >= '0' and ch <= '9')
			{
				digit += 1;
			}
		}

    else
        std::cout<<"\nbad stream\n";
}

///or

void countChars(fstream& file, int& upper, int& lower, int& digit)
{
    file.clear(); 
    file.seekg(0);

	if (file)
		while (file.get(ch))
		{
			if (ch >= 'A' and ch <= 'Z')
			{
				upper += 1;
			}
			else if (ch >= 'a' and ch <= 'z')
			{
				lower += 1;
			}
			else if (ch >= '0' and ch <= '9')
			{
				digit += 1;
			}
		}

    else
        std::cout<<"\nbad stream\n";
}
closed account (SECMoG1T)
consider a different approach where i load my file into a vector instead of directly working with a filestream;

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
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cctype>



// Declare functions
std::vector<std::string> loadFile(const std::string& fileName);
void printFileContent(const std::vector<std::string>& fileContent);
void countNPrintChars(const std::vector<std::string>& fileContent);


int main()
{
    std::string fileName("test.txt");

    auto  contentVec = loadFile(fileName);

    printFileContent(contentVec);
    countNPrintChars(contentVec);

    return 0;
}



std::vector<std::string> loadFile(const std::string& fileName)
{
    std::vector<std::string> _fileVec{};

    std::ifstream _fileStream(fileName);

    if(!_fileStream)
        std::cout<<"\nFailed to open file: <"<<fileName<<">\n";

    else
    {
        std::string _temp{};

        while(std::getline(_fileStream,_temp,'\n'))
            _fileVec.push_back(_temp);
    }

    return _fileVec;
}



void printFileContent(const std::vector<std::string>& fileContent)
{
    if(fileContent.size()) ///check to see if file open and was read properly
    {
       std::size_t _index = 1;

       std::cout<<"\n\tFile content\n";
       std::cout<<"    _______________________________\n";
       for(const auto& str : fileContent)
       {
           std::cout<<"\tline "<<_index++<<") "<<str<<"\n";
       }
    }

    else
        std::cout<<"\nproblem opening the file or the file might have been empty\n";
}




void countNPrintChars(const std::vector<std::string>& fileContent)
{
   std::size_t _upperCase = 0, _lowerCase = 0, _digit = 0, _totalAlphaNum = 0;

   for(auto str : fileContent)
   {
       for(auto chr : str)
       {
           if(std::isdigit(chr))
             ++_digit;

           else if(std::isupper(chr))
             ++_upperCase;

           else if(std::islower(chr))
             ++_lowerCase;
       }
   }

   _totalAlphaNum = (_digit + _upperCase + _lowerCase);

   std::cout<<"\n\n    _______________________________\n";
   std::cout<<"\tTotal # of characters  : "<<_totalAlphaNum<<"\n";
   std::cout<<"    _______________________________\n";
   std::cout<<"\tUppercase characters   : "<<_upperCase<<"\n";
   std::cout<<"\tLowercase characters   : "<<_lowerCase<<"\n";
   std::cout<<"\tTotal num of  Digits   : "<<_digit<<"\n";
}
Last edited on
I really appreciate the help from everyone, I have it working as desired now. I have a ways to go with c++ so I am very thankful for your patience!
Topic archived. No new replies allowed.