c++ toupper() to compare two strings - c++

I have created a set of algorithms that takes an input of a string vector, checks whether any of the strings occur more than once: if so erases all additional occurrences of the string from the vector, then outputs the new, 'lighter' array without the redundancies.
It works great except now I am to make it case-insensitive; I am attempting to simply add the toupper() std function to the == comparison statement, however it does not seem to work.
I have a more familiar background with Java and am trying to learn C++.
Can someone please show me how to correct my syntax?
// Output old list.
cout << endl << "==========\nOld list:\n==========";
for (int i = 0; i < count; i++) {
cout << endl << list[i];
}
cout << endl << endl;
// Check uniqueness.
for (int i = 0; i < count; i++)
for (int j = i+1; j < count; j++) {
if (toupper(list[i]) == toupper(list[j])) {
list[j] = "";
count--;
}
}
// Output new list.
cout << endl << "==========\nNew list:\n==========";
for (int i = 0; i < count; i++) {
cout << endl << list[i];
}
cout << endl << endl;

Your loop leaves "holes" in the list array vector, but the size of the array vector does not change (but you decrease your upper bound count)
There are probably many other alternatives, but if you don't want to modify it much, probably you need in an addtional loop to copy non-empty elements from the list array into a new array
Edit: integrating some of the answers
First we're going to have a function to do the toUpper (this is modified from #Jim22150)
std::string stringToUpper(const std::string &input) {
std::string toBeModified=input;
std::transform(toBeModified.begin(), toBeModified.end(), toBeModified.begin(), ::toupper);
return toBeModified;
}
Now, we must not leave holes, so we should use erase (as #Scott Christopher Stauffe indicated):
// Output old list.
cout << endl << "==========\nOld list:\n==========";
for (int i = 0; i < count; i++) {
cout << endl << list[i];
}
cout << endl << endl;
// Check uniqueness.
for (int i = 0; i < count; i++)
for (int j = i + 1; j < count; j++) {
if(stringToUpper(list[i]) == stringToUpper(list[j])) {
list.erase(j,1);
count--;
}
}
}
// Output new list.
cout << endl << "==========\nNew list:\n==========";
for (int i = 0; i < count; i++) {
cout << endl << newlist[i];
}
cout << endl << endl;

#DaveS, thanks Dave I will try that; it looks clean and short. However, I found dirtier solution using transform and making a duplicate of the old vector.
// Output old list.
cout << endl << "==========\nOld list:\n==========";
for (int i = 0; i < count; i++) {
cout << endl << list[i];
}
cout << endl << endl;
// Check uniqueness.
for (int i = 0; i < count; i++)
for (int j = i + 1; j < count; j++) {
std::transform(list[i].begin(), list[i].end(), list[i].begin(), ::toupper);
std::transform(list[j].begin(), list[j].end(), list[j].begin(), ::toupper);
if (list[i] == list[j]) {
newlist[j] = "";
count--;
}
}
// Output new list.
cout << endl << "==========\nNew list:\n==========";
for (int i = 0; i < count; i++) {
cout << endl << newlist[i];
}
cout << endl << endl;

If you want to handle C++ strings as easily as Java strings, then the Boost String Algorithms Library is the way to go. Installing Boost may be a bit hard for a newbie C++ programmer (although it's a breeze compared to many other C++ libraries), but it pays off.
Your problem will essentially be reduced to this:
boost::algorithm::to_upper_copy(list[i]) == boost::algorithm::to_upper_copy(list[j])

I just did a quick google of toupper and I didn't find any string versions of it. The only standard touppper() I have seen is int toupper(int c); - that means you can only use it to compare individual characters! Have you tried stricmp()?
if ( 0 == _stricmp(list[i], list[j]) ) {
list[j] = "";
count--;
}
Depending on your compiler you may or may not have this function at your disposal.

First of all,
list[j] = ""; // should never work.
You can remove a char by using erase.
list.erase(j, 1);
Alternatively, to avoid this altogether, you could use a temporary "builder" string and just push_back chars to it when needed.

Related

Is there a better and shorter way of my for loop?

I'm a newbie here and this my first question. I learn basic c++ on Visual Studio 2019. I study functions and loops.
I have a homework that wants print:
I solved it with my code of 30 lines. But I just wonder is a there a shorter and better way of this?
using namespace std;
int main()
{
for (int j = 0; j < 5; j++)
{
if (j == 1)
break;
cout << "*";
cout << endl;
if (j == 2)
break;
cout << "**";
cout << endl;
if (j == 3)
break;
cout << "***";
cout << endl;
if (j == 4)
break;
cout << "****";
cout << endl;
if (j == 5)
break;
cout << "*****";
cout << endl;
}
return 0;
}
You have made several mistakes in your code.
break statements should actually be continue statements. break terminates the entire loop altogether (ie. absolutely nothing will be printed in the code you provide).
i == 5 can never be true, as the loop terminates before thet happens (see the condition i < 5).
To answer your question, you can use a nested loop.
for (int i = 0; i < 5; i++) {
for (int j = 0; j <= i; j++) {
std::cout << '*';
}
std::cout << std::endl;
}
Or, if you don't need to be flexible, do it manually.
std::cout << "*\n**\n***\n****\n*****" << std::endl;
Why a loop? Here’s the same logic in seven lines of code:
int main() {
std::cout << "*\n";
std::cout << "**\n";
std::cout << "***\n";
std::cout << "****\n";
std::cout << "*****\n";
}
To be honest, this is probably as short as it gets (apart from cramming all the output into a single statement).
But the issue with your loop isn’t primarily its length, it’s that your loop isn’t variable: it fails to work as soon as you change the number of iterations, and that defeats the purpose. All the logic is hard-coded, which makes the loop useless.
But if you want to use loops, then make the logic of printing stars configurable:
void print_stars(int n) {
for (int i = 0; i < n; ++i) {
std::cout << "*";
}
std::cout << "\n";
}
int main() {
for (int i = 0; i < 5; ++i) {
print_stars(i + 1);
}
}
#include<iostream>
using namespace std;
int main(){
for(int i = 1;i <= 5;i++){
for(int j = 1;j <= i;j++){
cout<<"*";
}
cout<<"\n";
}
}
void printTrignleL(size_t n)
{
for (size_t i = 0; i < n; ++i) {
std::cout << std::string(i + 1, '*') << '\n';
}
}

C++ Lines not executing after a for loop. Loop not infinite

Most of the answers I'm coming across boil down to in infinite loop, but I've inserted some cout statements for diagnostic purposes and I'm thoroughly convinced this is not the case- it looks like the nested for loop finishes but simply skips over some lines before returning to the top of the outside for loop. The only time something gets pushed back is on the first iteration when the for nested loop is skipped completely. As is, the debugger gives an out of range vector fault, I assume because new unique items aren't being pushed back. Any ideas how to get around this?
Template <class T>
void count_unique(string filename, vector<T> input) {
vector<T> unique;
vector<int> count;
bool found = false;
ifstream fin;
fin.open(filename);
T line;
while (!fin.eof()) {
fin >> line;
input.push_back(line);
}
fin.close();
cout << input.size() << endl;
for (unsigned int i = 0; i < input.size(); i++) {
cout << input.at(i) << endl;
}
for (unsigned int i = 0; i < input.size(); i++) {
cout << input.at(i) << endl;
found = false;
for (unsigned int j = 0; j < unique.size(); i++) {
cout << unique.at(j) << "\t=\t" << input.at(i) << " ->" << unique.size() << endl;
if (input.at(i) == unique.at(j)) {
count.at(j)++;
found = true;
cout << "Incremented" << endl;
}
else {
cout << "None;" << endl;
}
}
cout << "Found=" << found << endl;
if (!found) {
unique.push_back(input.at(i));
count.push_back(1);
found = false;
cout << "Pushed back" << endl;
cout << "#";
for (unsigned int i = 0; i < unique.size(); i++) {
cout << unique.at(i) << "\t-\t" << count.at(i) << endl;
}
cout << "#" << endl;
}
}
for (unsigned int i = 0; i < unique.size(); i++) {
cout << "\t" << unique.at(i) << "\t=\t" << count.at(i) << endl;
}
}
Your inner loop incremements the wrong variable. It is actually an infinite loop, since j will never change. This is also why you get the out of range, i will continuously increase, beyond the size of input
//...
for (unsigned int i = 0; i < input.size(); i++) {
cout << input.at(i) << endl;
found = false;
for (unsigned int j = 0; j < unique.size(); j++) { // HERE

Memory leak when printing 2D array

I have memory leak when i print my 2D array, i looped in data from a vector into a vector called grid
Some indexes in Grid is null for example grid[8][8] is null, but grid[1][1] has a value of 3.
When i display indexes of grid with null value gives me a memory leak.
Below are my code, Any recommendations will be appreciated!
void populateAppendixB(vector<string> cityLocation, int **grid, int col, int row) {
vector<int> data = appendixB_data(cityLocation);
vector<string> appendixB_coordinates = getCoordinates(cityLocation);
vector<int> x_value = returncolValue(appendixB_coordinates);
vector<int> y_value = returnrowValue(appendixB_coordinates);
//loop data into grid[][]
for (int i = 0; i < x_value.size(); i++) {
grid[x_value[i]][y_value[i]] = data[i];
}
cout << " ";
//Top outer Grid
for (int i = 0; i < col + 2; i++) {
cout << " # ";
}
cout << " # ";
cout << endl;
//end
//y-axis
for (int j = row; j >= 0; --j) {
cout << " " << j << " # ";
for (int i = 0; i <= col; ++i) {
//displaying data
if(grid[i][j] == 0) {
cout << " ";
}
else {
cout << grid[i][j] << " ";
}
}
//Right outer Grid
cout << "#";
cout << endl;
}
//Last row of #
cout << " ";
for (int i = 0; i < col + 2; i++) {
cout << " # ";
}
cout << " # ";
cout << endl;
cout << " ";
//x-Axis
for (int i = 0; i <= col; i++) {
cout << i << " ";
}
cout << endl;
}
You use grid[x_value[i]][y_value[i]] = data[i];, but will not fill all of the grid since you only fill in one value of each column of grid (you only do this loop: for (int i = 0; i < x_value.size(); i++) {). Unless the grid passed in is pre-filled in with 0's properly (impossible to tell given your submitted code), then this is probably undefined behavior.
Even if it is a pre-filled in 2d array, when you print the elements of grid, you iterate from [0, cols] and [0, rows], which is likely not what you want (that iterates cols+1 columns and rows+1 rows. So, at least that last value will be accessing memory that is probably not valid.
As previous comments mention, it's a better idea to just use std::vector (e.g. std::vector<std::vector<int>> while using .at(i).at(j) to access elements which make use of C++ exceptions rather than accessing bad memory) or even std::array which are better at preventing and catching many issues cleanly. If you're worried about speed, it's probably not a huge deal and you can avoid copies by e.g. passing by reference, wrapping things in smart pointers if applicable, move semantics, etc.
I solved my problem by setting all my 2D array values to { }, then populate the grid array with the values that i want specifically.
It solves the memory leak problem but i am not sure if it is a good practice.

C++ Displaying An Organized List of Words

I am making a 20 questions game in C++ and have everything working, except for the displayWords function. The code I currently have keeps breaking. Any explanation would be appreciated! Thank you!
void displayWords()
{
int x = 0;
string words[50] = {"LCHS","Shark","Pencil","Pizza","New York","Fish","Car","Ice Cream","Los Angeles","Bird","Basketball","Fried Chicken",
"Dog","Tiger","Penguin","Plane","Rock","Barbecue Sauce","Mustard","Ketchup","Hot sauce","Peppers","Salt","Tacos","Shrimp","Pickels",
"Tomatos","Bannanas","Burger","Computer","Iphone","Motorcycle","Bicycle","Skateboard","Lightbulb","Golf Ball","Surfboard","Luggage",
"Rollercoaster","Cat","Lion","Cockroach","Grasshopper","Beach","Theme Park","Swimming Pool","Bowling Ally","Movie Theater","Golf Course","Shopping Mall"};
cout << "The following list of words are what the computer is capable of guessing" << endl;
cout << endl;
while(x < 50)
{
for (int y = 0; y <= 5; y++)
{
cout << words[x] << ", ";
if(x<50)
x++;
}
cout << endl;
}
}
I would like it to display the list of 50 words in an organized fashion.
By example, as:
for( int x = 0; x<sizeof(words)/sizeof(*words); x++ ) {
if( x%5==0 ) cout << endl; else cout << ", ";
cout << words[x];
}
take into account the problematic of the array's size calculation: see this link How do I find the length of an array?
If I understand correctly, you want your list displayed as 5 columns. Simplest way, use a nested for loop and proper formatting with std::setw (must #include <iomanip>):
for(size_t i = 0; i < 10; ++i)
{
for(size_t j = 0; j < 5; ++j)
{
std::cout << std::setw(20) << std::left << words[i * 5 + j];
}
std::cout << std::endl;
}
Your actual loop is incorrect, as it will lead to repetitions.
Maybe I'm not interpreting your question correctly but if you want to just print out the 50 words then you can use something like the code below. Not sure of the reason that the nested for loop iterating y was there.
Edit
void displayWords()
{
int x;
string words[50] = {"LCHS","Shark","Pencil","Pizza","New York","Fish","Car","Ice Cream","Los Angeles","Bird","Basketball","Fried Chicken",
"Dog","Tiger","Penguin","Plane","Rock","Barbecue Sauce","Mustard","Ketchup","Hot sauce","Peppers","Salt","Tacos","Shrimp","Pickels",
"Tomatos","Bannanas","Burger","Computer","Iphone","Motorcycle","Bicycle","Skateboard","Lightbulb","Golf Ball","Surfboard","Luggage",
"Rollercoaster","Cat","Lion","Cockroach","Grasshopper","Beach","Theme Park","Swimming Pool","Bowling Ally","Movie Theater","Golf Course","Shopping Mall"};
cout << "The following list of words are what the computer is capable of guessing" << endl;
cout << endl;
for(x = 0; x < words.size();x++)
{
cout << words[x]<< ", ";
}
}
Also some information on how the code is breaking, like are any errors being thrown or has debugging caused issues so far?

formatting phone number in c++

Please assist, I am trying to format a phone number like (111)111-1111. I have the following code which works but I would like to write much shorter.
int main(){
string phone_number;
cin >> phone_number;
cout<<"(";
for(int i = 0; i < 3; i++) {
cout << phone_number[i];
}
cout << ")";
for(int i = 3; i < 6; i++) {
cout << phone_number[i];
}
cout << "-";
for(int i = 6; i < 10; i++) {
cout << phone_number[i];
}
cout<<endl;
return 0;
}
please assist
Another possibility:
cout << "(" << phone_number.substr(0,3) << ")"
<< phone_number.substr(3,3) << "-" << phone_number.substr(6,4) << endl;
Use string::insert. But since you are taking a string as input, why wouldn't you give the input in format you need. Any how, this is how it can be done with out any loops if you wish to modify the string. In case you don't wish to change the original string then store the modified to a different temporary variable.
string phone_number = "123456789";
phone_number = phone_number.insert( 0, "(" ); // Original string is modified
// Rest can be achieved in similar fashion
cout << phone_number << endl;
for (int i=0; i<10; ++i)
{
if (i == 0) std::cout << '(';
else if (i == 3) std::cout << ')';
else if (i == 6) std::cout << '-';
std::cout << phone_number[i];
}
Probably wouldn't be good to change your data just to format.
string str(phn);
// Format Phone# 1: void function
printf("(%s)%s-%s",
str.substr(0,3).c_str(),
str.substr(3,3).c_str(),
str.substr(6, 4).c_str());
// Format Phone# 2: returns std::string&
stringstream p;
p << "(" << str.substr(0, 3) << ")"
<< str.substr(3, 3) << "-"
<< str.substr(6, 4);
return p.str();
Ignoring the question as to why you want to write this "shorter" ...
printf("(%c%c%c)%c%c%c-%c%c%c%c\n", phone_number[0], phone_number[1], phone_number[2],
phone_number[3], phone_number[4], phone_number[5],
phone_number[6], phone_number[7], phone_number[8],
phone_number[9]);
That being said - your code (nor this) checks to see if there's actually 10 numbers present, or if they're numbers at all. That above all is more important than wanting it "shorter".
Your code is too short, not too long. Any input from the user must always be checked for validity. For instance, what if the used already entered the punctuation, so that phone_number contains "(111)111-1111"? Then your code would output "((11)-)11-1-11" (I think). This is not what you want. At the very least, you must throw out all non-digit characters.
#include <iostream>
using namespace std;
int main(){
string phone_number;
cin >> phone_number;
cout<<"(";
for(int i = 0; i < 3; i++) {
cout << phone_number[i];
}
cout << ")";
for(int i = 3; i < 6; i++) {
cout << phone_number[i];
}
cout << "-";
for(int i = 6; i < 10; i++) {
cout << phone_number[i];
}
cout<<endl;
return 0;
}