How to add input to Text File?

This might be a simple question so I apologize. I have been making pace with a program that adds zoo animals to a text file in a list, and I am trying to let the user add a new animal to it if the animal isn't already on there, but the way I'm setting it (userInput = names[i]) is not working. The code I'm trying to fill is:

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
ifstream ifIn;
    ifIn.open("animals.txt");
    //checking whether the file name is valid or not
    if (ifIn.fail())
    {
        cout << "Error: File Not Found";
        return 1;
    }
    else
    {
        //Reading the data from the file
        while (ifIn >> names[count])
        {
            for (int j = 0;j < 2;j++)
            {
                ifIn >> animalNumber[count][j];
            }
            count++;
        }
 ifIn.close();

.... // checks if user wants to add animals

   cout << "What animal to add?" << endl;
                cin >> userAnimal;
                count = 0;
                if (checkAnimal(userAnimal, names[MAX_SIZE]) == false)//checks if userInput is 
                                                                                                     //already in file
                {
                    cout << userAnimal << " is already in the array" << endl;

                }
                else {
           userAnimal=names[i] // insert userAnimal input into array 
                }
            
           
....

bool checkAnimals(string animal, string name[MAX_SIZE]) {
    for (int i = 0; i < MAX_SIZE; i++) {
        if (animal == name[i]) {
            return false;
            break;
        }
    }
    return true;
}


As you can see, the line "Insert userAnimal input into array" is being done wrong but I cannot figure out how I would actually add user input into that text file/array. I am also not allowed to use any "append" openings. I also believe this is causing my "checkAnimals" function to have an error, "unresolved external symbol"
Thank you for any help!
Last edited on
Hello tgp23,

The parts of the program that are missing would be very helpful. It is best to post a complete program that can be compiled and tested. Which, if a large ptogram, just enough to demonstrate the problem.

In the line of code userAnimal=names[i] you not only missed the semi-colon at the end, but this takes the variable "userAniml" and sets it = to names[i]". I think what you want is the reverse.

It is hard to deduce what "animalNumber" is other than a 2D array, but of what type?

The function call, line 27, you just need the name of the variable not the "[MAX_SIZE]" part.

Just a small thing. Starting at line 12 call "count" "row" and "j" "col". it makes the code easier to understand and follow.

I would like to put your code in my IDE, but with what is missing it would be a waste of time right now.

Andy
Hello tgp23,

As I started working with your code I realized that you need to post your input file also.

Andy
Hello Andy,

I ended up nixing the check animals function and found a more efficient use of another function in my program to check it. That works, however the text file still doesn't have anything added to it after running my iteration I marked on here "iteration that doesnt run"(beginning line 80) so it could be easier to see where the issue is.
Here is my 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
111
112
113
114
115
116
117
118
119
120
#include <fstream>
#include <iostream>
#include <iomanip>
#include <string>


using namespace std;

const int MAX_SIZE = 20;
const int MAX_ROWS = 20;
const int MAX_COLUMNS = 2;

int search(string names[], int nos[MAX_ROWS][MAX_COLUMNS], int cnt, string searchName);

int main() {
    string decision;
    string userAnimal;
    string searchAnimal;
    string  names[MAX_SIZE];
    int animalNumber[MAX_ROWS][MAX_COLUMNS];
    int count = 0;
    //Declaring variables
    ifstream ifIn;
    ifIn.open("animals.txt");
    //checking whether the file name is valid or not
    if (ifIn.fail())
    {
        cout << "Error: File Not Found";
        return 1;
    }
    else
    {
        //Reading the data from file
        while (ifIn >> names[count])
        {
            for (int j = 0;j < 2;j++)
            {
                ifIn >> animalNumber[count][j];
            }
            count++;
        }
        ifIn.close();
        cout << "Add, Look, or Done?" << endl;
        cin >> decision;
        
            if (decision == "Look") // If user types in Look
            {

                cout << "Name to look up ? ";
                cin >> searchAnimal;
                while (searchAnimal != "Done")

                {
                    int number = search(names, animalNumber, count, searchAnimal);
                    if (number == -1)
                    {
                        cout << ">>> There is no data in the array for " << searchAnimal << endl;
                    }
                    else
                    {
                        cout << ">>> There are " << number << " " << searchAnimal << endl;
                    }
                    cout << "\nName to look up ? ";
                    cin >> searchAnimal;
                }

                cout << "Thank You!" << endl;
                return 0;

            } 
            else if (decision == "Add" || decision == "add") // if user types in add
            {
                while (decision == "Add")
                {
                    cout << "What animal to add?" << endl;
                    cin >> userAnimal;


                    int number = search(names, animalNumber, count, userAnimal);
                    if (number == -1) {
                        for (int i = MAX_SIZE - 1; i >= 19; i--) { // iteration that won't add anything
                            userAnimal = names[i];
                            cout << "It has been added" << endl;
                            break;
                        }
                    }
                    else {
                        cout << "It is already there" << endl;
                    }
                    cout << "Add, Look, or Done?" << endl;
                    cin >> decision;
                }
                
            } 
        

        else  {
            cout << "Good-bye!" << endl; // system ending
            return 0;
        }

            

        }
    return 0;
}


int search(string names[], int animalNumber[MAX_ROWS][MAX_COLUMNS], int count, string searchAnimal)
{
    for (int i = 0;i < count;i++)
    {
        if (names[i] == searchAnimal)
        {
            return animalNumber[i][0] + animalNumber[i][1];
        }
    }
    return -1;
}

Thank you for reaching out!
Last edited on
Hello tgp23,

Still need to post the input file so everyone can see what you are working with.

Now all you need is to add some blank lines and remove extra blank lines.

The code looks better, but it will take a little time to try and read it.


however the text file still doesn't have anything added to it after running


So where did you open an output stream to write to the file?

Andy
Here is what the text file looks like(animals.txt).
zebras 5 2
chimps 5 3
monkeys 4 4
ardvarks 1 2
dogs 3 5
tigers 4 2
frogs 10 12
lions 2 4
alligators 2 1
lizards 11 5
gerbils 14 12
goats 5 4
elephants 1 0
panthers 1 1
wolves 1 3
rhinoceros 1 1
hippos 1 1
gorillas 2 4

And I completely removed an output stream(ofstream) because when I tried that method, I would put...
1
2
3
4
5
6
7
8
ofstream ifOut;
ifOut.open("animals.txt");
string userAnimal;

...//check if opened correctly.
cin >> userAnimal;
ifOut << userAnimal << endl;


However this would remove the whole list and just put userAnimal alone.
Hello tgp23,

Thank you for the input file. It makes more sense now.

Your method of opening the output stream will wipe out or truncate whatever is in the file.

You could do this with 1 line as ofstrean outFile("animals.txt", std::ios::app);. This will set the file pointer at the end to append the file.

Something that would really help the program is if you can use a "std::vector". Much easier to work with and you do not need an initial fixed size like an array.

Andy
Andy,

How would I put in that vector? Would that be my "names" variable instead of the array?

Also I am not allowed to use the :app in this particular program because it hasn't been over yet, despite me already knowing of it from previous independent coding projects.

Thank you!
Last edited on
it would be a very petty jerk who told you you can't use app because he didn't say it in class. There is a line ... you don't use std::sort if the assignment is to write a sort yourself to study the algorithms, and you don't use list if the assignment is to do your own linked list, and so on, but this is a tiny thing and not using it is moronic.
The directions basically said nothing we learned thus far and after going through the notes, :app wasn't used once sadly, I agree though it does seem kinda dumb.

I placed in a function with a vector parameter, function titled ReadList. No prototype yet but it is declared at the bottom and used in the same line I had that for loop, this is at line 83. It is returning the error "Identifier Not Found" for some odd reason.
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

#include <fstream>
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <cstring>
#include <cstdlib>

using namespace std;

const int MAX_SIZE = 20;
const int MAX_ROWS = 20;
const int MAX_COLUMNS = 2;

int search(string names[], int nos[MAX_ROWS][MAX_COLUMNS], int cnt, string searchName);

int main() {
    vector <string> zooList;
    string decision;
    string userAnimal;
    string searchAnimal;
    string  names[MAX_SIZE];
    int animalNumber[MAX_ROWS][MAX_COLUMNS];
    int count = 0;
    //Declaring variables
    ifstream ifIn;
    ifIn.open("animals.txt");
    //checking whether the file name is valid or not
    if (ifIn.fail())
    {
        cout << "Error: File Not Found";
        return 1;
    }
    else
    {
        //Reading the data from file
        while (ifIn >> names[count])
        {
            for (int j = 0;j < 2;j++)
            {
                ifIn >> animalNumber[count][j];
            }
            count++;
        }
        ifIn.close();
        cout << "Add, Look, or Done?" << endl;
        cin >> decision;
        
            if (decision == "Look") // If user types in Look
            {

                cout << "Name to look up ? ";
                cin >> searchAnimal;
                while (searchAnimal != "Done")

                {
                    int number = search(names, animalNumber, count, searchAnimal);
                    if (number == -1)
                    {
                        cout << ">>> There is no data in the array for " << searchAnimal << endl;
                    }
                    else
                    {
                        cout << ">>> There are " << number << " " << searchAnimal << endl;
                    }
                    cout << "\nName to look up ? ";
                    cin >> searchAnimal;
                }

                cout << "Thank You!" << endl;
                return 0;

            } 
            else if (decision == "Add" || decision == "add") // if user types in add
            {
                while (decision == "Add")
                {
                    cout << "What animal to add?" << endl;
                    cin >> userAnimal;
                    int number = search(names, animalNumber, count, userAnimal);
                    if (number == -1) {
                            ReadList(zooList);
                            zooList.push_back(userAnimal);
                            cout << "It has been added" << endl;
                    }
                    else {
                        cout << "It is already there" << endl;
                    }
                    cout << "Add, Look, or Done?" << endl;
                    cin >> decision;
                }
                
            } 
        

        else  {
            cout << "Good-bye!" << endl; // system ending
            return 0;
        }

            

        }
    return 0;
}


int search(string names[], int animalNumber[MAX_ROWS][MAX_COLUMNS], int count, string searchAnimal)
{
    for (int i = 0;i < count;i++)
    {
        if (names[i] == searchAnimal)
        {
            return animalNumber[i][0] + animalNumber[i][1];
        }
    }
    return -1;
}
void ReadList(vector<string> &zooList) {
    ifstream inFS;
    string animal;

    inFS.open("animals.txt");

    if (!inFS.is_open()) {
        cout << "Could not open file animals.txt." << endl;
    }
    else {
        getline(inFS, animal);
        while (!inFS.fail()) {
            zooList.push_back(animal);
            getline(inFS, animal);
        }

        inFS.close();
    }
}
Last edited on
Hello tgp23,


How would I put in that vector? Would that be my "names" variable instead of the array?


To make a more proper use of a vector I would first create a struct. Something like:
1
2
3
4
5
6
7
8
9
10
11
12
13
struct Animal
{
    std::string s_name;
    int s_?{};
    int s_?{};

    Animal(std::string name, int ?, int ?)
{
    s_name = name;
    s_? = ?;
    s_? = ?;
}
};

Since I do not know what the numbers are for I do not know what to call them.

Then what you would have is std::vector<Animal> animals;
After you input the name and 2 ints you would use animals.emplace_back(name, int?, int?); where "int?" is the name of the variable.

But if you can not use "app" with the "ofstream" then you are not likely to be able to use a vector yet.

Although the idea of the struct can still be used with an array.

For what it is worth looking at:
1
2
3
4
5
6
7
8
while (inFile >> names[count])
{
    for (int j = 0; j < 2; j++)
    {
        inFile >> animalNumber[count][j];
    }
    count++;
}

This could be shortened to:
1
2
3
4
5
6
while (inFile >> names[count])
{
    inFile >> animalNumber[count][0] >> animalNumber[count][1];

    count++;
}

As a suggestion "inFile" is more descriptive than "ifIn". And I like to use "outFile" for an output stream.

The for loop is a bit over kill for just 2 columns.

When I get to this:
1
2
3
4
cout << "Add, Look, or Done? ";
cin >> decision;

if (decision == "Look") // If user types in Look 

You are asking a lot of any given user here to enter the word correctly. This if statement is comparing to "Look", but the else if is comparing "Add" and "add". What happen if the caps lock key is on and someone types in "aDD" or "lOOK".

It would be simpler to either define "decision" as a "char" or just check "decision[0]". One disadvantage to using a "char" is that there might be more characters left in the input buffer that would need to be cleared.

One thing that you can count on is on any given day with any given user someone will break your program with out even trying.

In the if statement consider this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if (decision == "Look") // If user types in Look
{
    //cout << "\nName to look up? ";
    //cin >> searchAnimal;

    while (cout << "\nName to look up? (Done to quit): " && cin >> searchAnimal && searchAnimal != "Done")
    {
        int number = search(names, animalNumber, count, searchAnimal);

        if (!number)
        {
            cout << ">>> There is no data in the array for " << searchAnimal << '\n';
        }
        else
        {
            cout << ">>> There are " << number << " " << searchAnimal << '\n';
        }

        //cout << "\nName to look up ? ";
        //cin >> searchAnimal;
    }

    cout << "Thank You!" << endl;
}

The return statement at the end is not needed because the else ifs and will be bypassed leaving at the last line of "main" before the closing brace. Also the return in the else statement is not needed.

The "add" need reworked to output to a file. Not being able to use "app" you would have to write the part of the arrays used to the file. You would also need a variable to keep track of how much of the array is used or step through the array until you find an empty name.

Should have mentioned this earlier. It is always best to initialize your variables when they are defined.
1
2
int animalNumber[MAX_ROWS][MAX_COLUMNS]{};
int count{};

The empty {}, or the uniform initializer, available from C++11 on, will let the compiler choose what is the best form of zero to give the variable. Or you could put a number between the {} if you need.

Strings are empty when defined and do not need initialized.

Andy

Hello tgp23,

Thought you were done. Anything else I can do will have to wait until the morning for me.

I like the idea of using the vector, but I do not believe the code that you posted is making the best use of a vector.

Andy
Hello tgp23,

You get an A for effort and a good attempt for using the vector, but an F for failing to use it properly.

I would start the program by creating the vector early, well before "Add". Then you can make better use of it in the program.

Also by creating the vector early you can determine if the file exists before the program goes to far.

The idea of the vector was to eliminate the need for the arrays, but you still have them and the arrays are still a potential problem unless you want to make them with a size of 100 to start with. The point of the vector is to eliminate the unused part of the arrays.

I will start with these 2 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
int search(string names[], int animalNumber[MAX_ROWS][MAX_COLUMNS], int count, string searchAnimal)
{
    for (int i = 0; i < count; i++)
    {
        if (names[i] == searchAnimal)
        {
            return animalNumber[i][0] + animalNumber[i][1];
        }
    }

    return 0;  // <--- Return (0) or false meaning that no match was found.
}

int ReadList(vector<string> &zooList)
{
    ifstream inFS;
    string animal;

    inFS.open("animals.txt");

    if (!inFS)  // <--- This is all you need.
    {
        cout << "Could not open file animals.txt.\n\n";

        return 2;
    }
    //else  // <--- This is not needed. Just extra work.
    //{

        while (getline(inFS, animal))
        {
            zooList.push_back(animal);
        }

        inFS.close();
    //}

    return 0;
}

The "return"s are better done this way as you will see shortly.

For "Add":
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if (!number)
{
    if (!(ReadList(zooList)))
    {
        zooList.push_back(userAnimal + ' ' + std::to_string(2) + ' ' + std::to_string(3));

        cout << "It has been added" << endl;
    }
    else
    {
        std::cerr << "\n     File was not open or read!\n\n";
    }

}
else
{
    cout << "It is already there" << endl;
}

Be it an if, while, for or while in a do/while condition whatever is in the () is eventually converted to a bool value. You can use this to your advantage. That is why all you need is if (!number). A returned value of (0) becomes true and any other number becomes false.

The same concept applies to if (!(ReadList(zooList))). Also this should be done before the "Add" section.

Line 5 is what you should be doing to add to the vector. the numbers in () would need to be changed to a user input.

Also you have added to the vector, but not to the arrays. As is you could only add 2 animals to the arrays before you would have to change the size of the array. I also noticed there is nothing in the "Add" section to know when the array is full.

Using a vector would alleviate this problem.

And I did not see any code to write the vector to a file.

As I showed you earlier using a struct and a vector of structs would eliminate many potential problems with using arrays.

I need some more time to rework what you have and see what I can come up with.

Andy
Using a vector, splitting into functions and re-saving data when done, consider C++17:

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

struct Animal {
	std::string name;
	int n1 {};
	int n2 {};
};

std::vector<Animal> readData();
int search(const std::vector<Animal>&, const std::string&);
void add(std::vector<Animal>&);
void look(const std::vector<Animal>&);
bool save(const std::vector<Animal>&);

int main() {
	auto zooList {readData()};

	if (zooList.empty()) {
		std::cout << "Cannot open/read file\n";
		return 1;
	}

	for (std::string decision; std::cout << "Add, Look, or Done? " && std::cin >> decision; )
		if (decision == "Look" || decision == "look")
			look(zooList);
		else
			if (decision == "Add" || decision == "add")
				add(zooList);
			else
				if (decision == "done" || decision == "Done") {
					if (save(zooList))
						std::cout << "Data saved ok\n";
					else
						std::cout << "Problem saving data\n";

					std::cout << "Good-bye!\n";
					break;
				} else
					std::cout << "Unknown option\n";
}

int search(const std::vector<Animal>& zoo, const std::string& searchAnimal)
{
	for (const auto& [name, n1, n2] : zoo)
		if (name == searchAnimal)
			return n1 + n2;

	return -1;
}

std::vector<Animal> readData()
{
	std::vector<Animal> zooList;
	std::ifstream ifIn("animals.txt");

	if (ifIn.is_open())
		for (Animal an; ifIn >> an.name >> an.n1 >> an.n2; zooList.push_back(an));

	return zooList;
}

void look(const std::vector<Animal>& zooList)
{
	for (std::string searchAnimal; (std::cout << "Name to look up (Done to quit)? ") && (std::cin >> searchAnimal) && (searchAnimal != "Done" && searchAnimal != "done"); ) {
		const auto number {search(zooList, searchAnimal)};

		if (number == -1)
			std::cout << ">>> There is no data in the array for " << searchAnimal << '\n';
		else
			std::cout << ">>> There are " << number << " " << searchAnimal << '\n';
	}
}

void add (std::vector<Animal>& zooList)
{
	for (Animal an; (std::cout << "What animal to add (Done to quit)? ") && (std::cin >> an.name) && (an.name != "done" && an.name != "Done"); )
		if (search(zooList, an.name) == -1) {
			std::cout << "Enter n1 n2: ";
			std::cin >> an.n1 >> an.n2;

			zooList.push_back(an);
			std::cout << "It has been added\n";
		} else
			std::cout << "It is already there\n";
}

bool save(const std::vector<Animal>& zooList)
{
	std::ofstream ofOut("animals.txt");

	if (ofOut.is_open()) {
		for (const auto& [name, n1, n2] : zooList)
			ofOut << name << ' ' << n1 << ' ' << n2 << '\n';

		return true;
	}

	return false;
}

Last edited on
Topic archived. No new replies allowed.