Searching string for a partial string, using structures: displays both 'found' and 'not found' statements?

This is for a program that uses structures to store data. customer[k] is the structure that holds data for customer at index k, and it is looking through the structure member customerName (a string) to find a string entered by the user (name) passed in from a different function. SIZE is the total amount of customer accounts possible, which is only 2.

the function findCustomer does exactly what it says: looks through the names stored for each customer to find a match for the search term input by the user, and displays what it finds (using a different function), or doesn't find.

I am trying to use a for loop to iterate through the two different customer 'files'. And then using an if statement, using .find() to... find what was searched for. It has to be able to look for full or partial matches, and has to be strings, not c-strings (so strstr is out of the question).

The issue is my if statement. It outputs the second if statement first (did the same thing when i had it as an 'else'), then the first one if it finds a match. If it does not find a match, it does what it's supposed to and only shows the second if statement.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void findCustomer(string name)
{
	for (int k = 0; k < SIZE; k++)
	{
		string existingName = customer[k].customerName;
		if (existingName.find(name) != string::npos)
		{
			cout << "\n** Customer found! **" << endl;
			cout << "\n** Info for customer #" << (k + 1) << " **" << endl;
			cout << "\t----------\t" << endl;
			displayCustomer(k);
		}
		if (existingName.find(name) == string::npos)
		{
			cout << "\n** No customer on file matches your search! **" << endl;
		}
	}
}


Why is it doing this?
The second if is wrong within the loop. Just use a bool:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void findCustomer(string name)
{
	bool found = false; // Note
	for (int k = 0; k < SIZE; k++)
	{
		string existingName = customer[k].customerName;
		if (existingName.find(name) != string::npos)
		{
			found = true; // Note
			cout << "\n** Customer found! **" << endl;
			cout << "\n** Info for customer #" << (k + 1) << " **" << endl;
			cout << "\t----------\t" << endl;
			displayCustomer(k);
		}
	}
	if (!found)
	{
		cout << "\n** No customer on file matches your search! **" << endl;
	}
}
Okay, it's working a little better now. However it's still displaying the second if statement when it finds a match for the second user file. It displays how it should when it finds a match for the first user file, and how it should when it finds no matches.

It's really weird and I'm not entirely sure why it would be doing that.
You've not show us any code that deals with any kinds of files, so there's little we can do to help you with that.

Also, where does the function findCustomer get the array customer from?
I didn't want to post the entire code because it is pretty long and I figured no one would read it, besides the rest of the program works perfectly. The loop in this function is the only issue I am having. I tried to explain and give context for what the variables are but if you want me to show you all of the code for some reason, I guess I can.
if you want me to show you all of the code for some reason

What do you mean, "for some reason"? You were talking about a problem you were having with your program finding matches in some "second file". I was explaining that you haven't shown us any code that might be relevant to that, so we can't help you with it.

Do you want help with that problem, or not?
if you want me to show you all of the code for some reason, I guess I can.
Better not all the code. Rather minimal compilable code with main().

Just fill customer[k].customerName with the names in question. displayCustomer(k); can probably omitted too.
I'm sorry, I didn't think I would have to show more than where I'm having the issue since the rest of it works how it should. I'm new to this. I wouldn't have posted if I didn't want help.

So, like I said this uses structures. There's no actual 'files', I just say that for lack of a better term.

Here's the structures I'm using:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct Date
{
	int month;
	int day;
	int year;
};

struct Address
{
	string streetAddress;
	string city;
	string state;
	string zip;
};

struct CustomerAccounts
{
	string customerName;
	Address customerAddress;
	string phoneNumber;
	double currentBalance;
	Date lastPayment;
};


After that is my function prototypes, and then these declarations:

1
2
const int SIZE = 2;
CustomerAccounts customer[SIZE];


Only 2 accounts can be entered (so I don't sit there and enter 20 just to test it).

Here is my main function. I omitted everything that isn't pertinent to the issue, but if you need to see something else please just ask me.

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
int main()
{
	cout << "This program allows you to enter, edit, display, and" << endl;
	cout << "search for the information of 2 different customers." << endl;

	int choice;
	int customerNum = 0;
	bool cont = true;

	do
	{
		displayMenu(); // Function that literally just displays menu options 1-5.
		cin >> choice;

		switch (choice)
		{
		case 1: // Option 1 displayed from menu is the ability to add a new customer account.
		{
			if (customerNum < SIZE)
			{
				cout << "Please enter customer #" << (customerNum + 1) << "'s information." << endl;
				cout << "\t----------\t" << endl;
			}
			enterCustomer(customerNum);
			customerNum++;

			break;
		}
		case 2:
		{
			// Omitted, irrelevant; lets user enter a customer account number for the account 
// they want to edit info for, then calls enterCustomer(customerNum), works perfect.

			break;
		}
		case 3:
		{
			//Omitted, irrelevant, calls displayCustomer(customerNum); function to display all 
// existing customer accounts, works perfect.

			}
			break;
		}
		case 4: // This is where the issue could be, option 4 is to search for a customer by
// name, then displaying their info from inside the function.
		{
			string findName;

			cout << "\nEnter the full or partial name of the customer # you want to find: ";
			cin.ignore();
			getline(cin, findName);
			findCustomer(findName);

			break;
		}
		case 5: // Option 5, quits program
		{
			cout << "\nThank you for using this program." << endl;
			cont = false;
			break;
		}
		default:
		{
			cout << "\n** Please make a valid selection! **" << endl;
			break;
		}
		}
	} while (cont == true);

		return 0;
}


Then of course is the function I'm having an issue with.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void findCustomer(string name)
{
	bool found = false;

	for (int k = 0; k < SIZE; k++)
	{
		string existingName = customer[k].customerName;
		if (existingName.find(name) != string::npos)
		{
			found = true;
			cout << "\n** Customer found! **" << endl;
			cout << "\n** Info for customer #" << (k + 1) << " **" << endl;
			cout << "\t----------\t" << endl;
			displayCustomer(k);
		}
		if (!found)
		{
			cout << "\n** No customer on file matches your search! **" << endl;
		}
	}
}


If this isn't clear please let me know and I'll add in whatever will help.
Last edited on
Do you mean this (not tried):

1
2
3
4
5
6
7
8
9
10
11
12
13
void findCustomer(const string& name)
{
	for (int k = 0; k < SIZE; ++k) {
		if (customer[k]) == name) {
			cout << "\n** Customer found! **\n";
			cout << "\n** Info for customer #" << (k + 1) << " **\n";
			cout << "\t----------\n";
			displayCustomer(k);
			return;
		}

		cout << "\n** No customer on file matches your search! **\n";
}

Unfortunately not, because I need to be able to search for a partial match of a name. Say the user wants to search for an account with a name that contains 'St', they enter that and it gets stored in the string findName in main(), then passed to findCustomer() as the string name. the structure customer, and it's member customerName (hence customer[k].customerName, where k is the customer number) it pulled up if there is a match.

Also wouldn't having the "not found" message outside the if statement still just display both if it does find a match? (I haven't tried this either because of the issue with the if statement itself).
Just tried your code, unfortunately it didn't work as I intended and actually displayed the "not found" message twice before the found message instead of once, so that's an odd thing. But it did make me think of something...

Interestingly, when I do this (commenting out second if statement):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void findCustomer(string name)
{
	bool found = false;

	for (int k = 0; k < SIZE; k++)
	{
		string existingName = customer[k].customerName;
		if (existingName.find(name) != string::npos)
		{
			found = true;
			cout << "\n** Customer found! **" << endl;
			cout << "\n** Info for customer #" << (k + 1) << " **" << endl;
			cout << "\t----------\t" << endl;
			displayCustomer(k);
		}
		/*if (!found)
		{
			cout << "\n** No customer on file matches your search! **" << endl;
		}*/
	}
}


it works perfectly, aside from not displaying a message when it doesn't find anything.

When I comment it back in, the "not found" message displays before the "found" message only if the match is found at customer[1].customerName, and does not display the "not found" message when a match is found at customer[0].customerName.

I suppose I could just go without the "not found" message entirely, and that would solve the issue. But I really would like it to at least say something. I feel like the solution is probably very simple but somehow I'm just not seeing it.
Sorry for the spam! But I got it... I needed two if statements, one inside the loop to search and flag a match and one outside the loop.

Looks a little weird but it works as intended!

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
void findCustomer(string name)
{
	bool found = false;
	int customerFound;

	for (int k = 0; k < SIZE; k++)
	{
		string existingName = customer[k].customerName;
		if (existingName.find(name) != string::npos)
		{
			found = true;
			customerFound = k;
		}
	}

	if (found == true)
	{
		cout << "\n** Customer found! **" << endl;
		cout << "\n** Info for customer #" << (customerFound + 1) << " **" << endl;
		cout << "\t----------\t" << endl;
		displayCustomer(customerFound);
	}
	else
	{
		cout << "\n** No customer on file matches your search! **" << endl;
	}
}


The problem was that as it was searching, if it found a match it would display the info for what it found, and if the second index did not match, it would run through the loop and display the "not found" message. Makes perfect sense in hindsight but... oh well.

Thank you!
yea you can clean it a little, but that is good work. Removing the extra string and unnecessary bool: note that 0 is false. note that you need k+1 anyway, as the goal is a print.
line 9 would be a lot of slowdown from copying if you kept it your way and did a large number of entries (size very large). it could have been a reference, if you find the long access cumbersome (say you needed to talk about it 20 times instead of just once)
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

void findCustomer(string name)
{
	bool found = false;
	int customerFound{0};

	for (int k = 0; k < SIZE; k++)
	{
		string existingName = customer[k].customerName;
		if (customer[k].customerName.find(name) != string::npos)
		{
			found = true;
			customerFound = k+1;
		}
	}

	if (customerFound)
	{
		cout << "\n** Customer found! **" << endl;
		cout << "\n** Info for customer #" << (customerFound ) << " **" << endl;
		cout << "\t----------\t" << endl;
		displayCustomer(customerFound-1);
	}
	else
	{
		cout << "\n** No customer on file matches your search! **" << endl;
	}
}


endl is also doing more than just end of line. get in the habit of using \n instead, and endl only sparingly.
Last edited on
Oh awesome! I’ll have to try that. Looks so much better, I had seen people do this sort of thing that way but was unsure of myself in applying it. I would have used reference variables but since the program only needs two customer accounts (and since my understanding is poor to begin with) I figured it would be ok to bypass that this time around.

Also thanks for the tip about endl, I WAS using \n and my professor (who doesn’t even actually teach at all and answers emails only once every two weeks, hence why I’m here…) took points off my last program and told me to use endl. :P Frustrating.
Are you aware that you display only the last occurrence? What does the requirement say?

Your mistake was that you still had the if(!found) inside the loop but it has to be outside
Perhaps (not tried):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void findCustomer(const string& name) {
	size_t customersFound {};

	for (int k = 0; k < SIZE; ++k) {
		const auto& existingName {customer[k].customerName};

		if (existingName.find(name) != string::npos) {
			cout << "\n** Customer found! **\n";
			cout << "\n** Info for found customer #" << ++customersFound << " **\n";
			cout << "\t----------\n";
			displayCustomer(customersFound - 1);
		}
	}

	if (!customersFound)
		cout << "\n** No customer on file matches your search! **\n";
}

Topic archived. No new replies allowed.