String array homework - c++

So i have a hw problem for my class where i have to store ten names, capitalize them and then sort them alphabetically. We just started using strings and there are some things that are still a little confusing to me. This code can store all the names in a string array, but the UpperCase seems to not be working. I dont know for sure but i think it is because I have second for loop running cap amount of times, which would be 10. And since not every string will have 10 elements, i'm running into problems?..Is that it or is it something else? Well i tried to fix this by using the .length (function?), to find the length of each name in the array, but I always get errors. Any help is appreciated, thanks!
#include<iostream>
#include<string>
using namespace std;
void UpperCase(string names[],int cap);
void print(string names[],int cap);
void swap(string names[],int &x,int &y);
string names[10];
int main(){
char a;
cout<<sizeof(a);
for(int i=0;i<10;i++){
cout<<"Enter a name for student "<<i+1<<" : ";
cin>>names[i];
cout<<endl;
}
UpperCase(names,10);
cout<<endl;
print(names,10);
cout<<endl;
print(names,10);
return 0;
}
void print(string names[],int cap){
for(int i=0;i<cap;i++)
cout<<names[i]<<endl;
}
void UpperCase(string names[],int cap){
for(int student=0;student<cap;student++){
for(int letter=0;letter<names[student].length();letter++){
if(names[student][letter]>='a')
names[student][letter]-=('a'-'A');
}
}
}

Your inner loop should be iterating for the length of the string. string::length() is a function, not a field, so you need the parentheses. There's also a standard library function for converting a character to upper case.
#include <cctype>
using std::toupper;
void UpperCase(string names[],int cap){
for(int student=0;student<cap;student++){
for(int letter=0;letter<names[student].length();letter++){
names[student][letter] = toupper(names[student][letter]);
}
}
}

..., but the UpperCase seems to not be working
So write a minimal program that just calls UpperCase on known input. It makes it easy to debug, and would also make a much better question. We don't need to see the print or swap to help with that, and prompting the user for input isn't relevant to whether UpperCase works or not.
Having said that, you should use std::string::length() - however, you say
Well i tried to fix this by using the .length (function?), to find the length of each name in the array, but I always get errors
but don't show what you actually tried, or what the errors were.
Here's a minimal, complete and self-contained program, using std::toupper as per T.C.'s answer. I changed it to demonstrate more modern style, and to show there are easier ways to confirm your functions work than to write a whole program and then find out it's broken.
#include <algorithm> // for transform, for_each
#include <cctype> // for toupper
#include <string>
#include <vector> // easier to use (correctly) than bare arrays
// change a string to upper case
void str_toupper(std::string &s) {
std::transform(s.begin(), s.end(),
s.begin(),
[](char c) -> char { return std::toupper(c); });
}
// change a vector of strings to upper case
void vec_toupper(std::vector<std::string>& v) {
std::for_each(v.begin(), v.end(), str_toupper);
}
using namespace std;
int main() {
vector<string> const input = { "bob", "alice cooper", "Eve" };
vector<string> const expected = { "BOB", "ALICE COOPER", "EVE" };
vector<string> working = input;
vec_toupper(working);
return working == expected ? 0 : -1;
// use cout or debugger to solve problem only if program returns nonzero
}

Related

count letters in a string c++

I am trying to write a function that counts the number of characters in a string excluding spaces. However, the output is always wrong so there is something wrong with my code.
There is something wrong with my code but I can't figure it out. Please help me with my programming homework.
#include <iostream>
#include <bits/stdc++.h>
#include <stdio.h>
#include <ctype.h>
using namespace std;
int countLetters (char s[], int size_s){
int isLetter = 0;
for(int i =0; i<size_s;i++){
if (isalpha(s[i])){
isLetter ++;
}
}
return isLetter;
}
int main (){
char s[100];
gets(s);
int n = sizeof(s)/sizeof(s[0]);
cout << countLetters(s,n);
}
Here is an example of the wrong output:
hi
10
PS C:\Users\user\OneDrive\Desktop\cpp practical> cd "c:\Users\user\OneDrive\Desktop\cpp practical\" ; if ($?)
{ g++ count_letters.cpp -o count_letters } ; if ($?) { .\count_letters }
hi
6
PS C:\Users\user\OneDrive\Desktop\cpp practical> cd "c:\Users\user\OneDrive\Desktop\cpp practical\" ; if ($?)
{ g++ count_letters.cpp -o count_letters } ; if ($?) { .\count_letters }
hi
10
PS C:\Users\user\OneDrive\Desktop\cpp practical>
To begin with, I think your information source, like PepijnKramer, said in the comments, is a bit old. There are much easier data types you can use to complete this problem like std::string below.
First of all, your code is redundant in its header files: #include <bits/stdc++.h> is a nonstandard header, and you already have all the libraries you need.
Secondly, your main problem comes from the lines
char s[100];
gets(s);
int n = sizeof(s)/sizeof(s[0]);
You see, you first create a char array called s with 100 elements. However, you never give them an initial value, so the random garbage that came with the initialization stays. However, C++ also does not reset the values, so some of them may be randomized into letters. Then, you just use gets() to input the string. However, gets() only fills the array s with the number of characters you entered. Therefore, if you do not enter 100 characters, the random garbage that still can be a letter remains. Finally, when you do the size with the integer n, it turns out the result is always 100 because you defined s to have 100 elements, so when you run the function, you still iterate over the garbage in the array s. Therefore, depending on chance of what the garbage includes, your output is incorrect. To solve this, you can either you make sure to initialize it by
char s[100] = { };
Or switch a datatype. Here is a correct solution using std::string:
#include <bits/stdc++.h>
using namespace std;
int countLetters (string a, int size_s){
int isLetter = 0;
for (int i = 0; i < size_s; i++) {
if (isalpha(a[i])){
isLetter++;
}
}
return isLetter;
}
int main () {
string s;
getline(cin, s);
cout << countLetters(s, s.length());
}

reversing the letters of the words in a string

I want to reverse the letters of the words in a string and have to store it in the same array.example: i/p: hi how are you o/p: ih woh era uoy. i wrote this programs but it just prints the same string without reversing and the program is not terminating it continues to print something. i cant findout the mistake. please help me and tell me the correct code.
#include<iostream.h>
#include<conio.h>
#include<stdio.h>
void stre(char (&a1)[20], int j1, int i1)
{
char b[20];
for(int k=i1-j1;k<i1;k++)
b[k]=a1[i1-k-1];
for(k=i1-j1;k<i1;k++);
a1[k]=b[k];
}
void main()
{
clrscr();
int j;
char a[20];
gets(a);
for(int i=0;a[i]!='\0';i++)
{
j++;
if(a[i]==' ')
{
stre(a,j,i);
j=0;
}
}
stre(a,j,i);
for(j=0;j<i;j++)
cout<<a[j];
getch();
}
friends after your answers i removed the semicolon in the for loop and also initialized j=0 but still i am not able to get the required output now for the i/p:hi how are you o/p:ihh hi hhi hhi. still need your help.
for(k=i1-j1;k<i1;k++);
a1[k]=b[k];
The semilcolon after the for loop prevents the last action from occuring multiple times.
try
#include <iostream>
using namespace std;
int main() {
int j =0;
char a[20] = "hi how are you";
char b[20] = "";
int l=0;
for(int i=0;a[i]!='\0';i++){
if(a[i]==' ' ||a[i+1]=='\0'){
cout<<j<<' '<<i;
if(a[i+1]=='\0'){
b[l++] = ' ';
}
for(int k=i;k>=j;k--){
b[l]=a[k];
l++;
}
for(int k=j;k<=i;k++){
cout<<b[k];
a[k] = b[k];
}
cout<<endl;
j = i+1;
}
}
cout << a;
return 0;
}
This for loop is terminated by the semi-colon:
for(k=i1-j1;k<i1;k++);
^^^
Here's a version that is not perfect by any means, but at least, it tries to be more like C++ than C:
http://ideone.com/f5vciW
first: tokenize into words and space sequences
//the spaces should be preserved
std::string test("hi how are you"),reference("ih woh era uoy");
std::vector<std::string> tokens;
tokenize(test,tokens);
then reverse the tokens
for (auto& token : tokens)
std::reverse(token.begin(),token.end());
assemble tokens into a string buffer
std::stringstream buf;
for (auto token : tokens)
buf<<token;
check the result
std::string res=buf.str();
assert(res==reference);
where the tokenizer looks like that:
template <typename TContainer,typename TString>
void tokenize(TString input,TContainer& res)
{
if (input.length()<2) {
res.push_back(input);
return;
}
typename TString::const_iterator pos=input.begin();
bool space_state=std::isspace(input[0],std::locale());
for (typename TString::const_iterator it=input.begin(); it!=input.end();
++it) {
bool is_space=std::isspace(*it,std::locale());
if (is_space!=space_state) {
res.push_back(TString(pos,it));
pos=it;
space_state=is_space;
}
}
//the rest
if (pos!=input.end()) {
res.push_back(
TString(
pos,
static_cast<typename TString::const_iterator>(input.end())
));
}
}
you passed j without assigning the value. so it will be garbage.
I can see two things in your code that may not result in the expected output:
1)
int j;
should be replaced with
int j=0;
And
for(k=i1-j1;k<i1;k++);
a1[k]=b[k];
the semicolon after the for loop needs to be removed.
FYI, this mixing of C and C++ code is not recommended (it's compromising readability). please stick to either one of them.
A similar example is shown on this site. They've also used almost the same approach that you'v e chosen(reversing each word by counting number of spaces) by with the help of stack data structure.
Make sure you have the STL library installed in your environment to run this code. Better run this code on linux platform.
Here's another, shorter version, doing the inversion in-line without using an extra buffer:
http://ideone.com/hs9NZ7
the criterion for the tokenizer is the change in the isspace condition:
auto next_token=
[&](char c) {
return std::isspace(c,loc)!=std::isspace(*pos,loc);
};
using that we can go through the input string and visit the tokens:
for (auto it=std::find_if(pos,test.end(),next_token);
it!=test.end();
it=std::find_if(pos,test.end(),next_token))
reversing them and updating the current position
std::reverse(pos,it);
pos=it;
and not forgetting the leftover token.

Prog error: for replacing spaces with "%20"

below is the prog i am compiling for replacing spaces with "%20" but when I run it output window shows blank and a message "arrays5.exe has occurred a prob"
#include <iostream>
#include<cstring>
using namespace std;
void method(char str[], int len) //replaces spaces with "%20"
{
int spaces, newlen,i;
for (i=0;i<len;i++)
if(str[i]==' ') spaces++;
newlen=len+spaces*2;
str[newlen]=0;
for (i=len-1;i>=0;i--)
{
if(str[i]==' ')
{
str[newlen-1]='0';
str[newlen-2]='2';
str[newlen-3]='%';
newlen=newlen-3;
}
else
{
str[newlen-1]=str[i];
newlen=newlen-1;
}
}
}
int main()
{
char str[20]="sa h ";
method(str,5);
cout <<str<<endl;
return 0;
}
Please help me finding the error.Thanks
spaces is uninitialised before you increment it.
You should give it an initial, default value.
An uninitialised variable will have a value which is undefined by the specification. This value could be 0, if you're lucky but it is highly likely that this value will be anything in the range of values which the datatype may represent.
Your program will compile and run fine when spaces is initialised properly.
I'm not fixing your problem, but providing a better solution. If you're using C++, then you should use the STL. You've got lots of classes and methods that do all of the job for you.
You could rewrite your 25 lines long method into this 4 lines long method(example included):
#include <iostream>
#include <string>
using namespace std;
std::string method(std::string str)
{
size_t index;
while((index = str.find(' ')) != std::string::npos)
str = str.replace(index, 1, "%20");
return str;
}
int main()
{
std::string str("sa h ");
str = method(str);
cout <<str<<endl; // outputs sa%20h%20
return 0;
}
I would suggest you use std::string, and use the .replace method. The reason your code doesn't work is because you're overwriting the input string in an odd way so I don't know if your expected output would be correct, however, the actual error you have is that you're potentially rewriting at index locations -3, -2, and -1. Consider the case where your first space is at index zero.
In C++, it's usually better to avoid char* unless you have a clear reason for doing so. As a matter of good style (this is somewhat subjective), I would suggest that you do NOT modify your input arguments directly, but instead return the result.
Ie, your method prototype should be:
std::string method(std::string str)
There is no-longer a need to pass the length of the string, because std::string takes care of that.

Count matches in an array

I can't figure out how to do this.
The question: Implement the function
int count_matches(const string arr[], int size, string query);
Return the number of strings in the array that are equal to query or
-1 if size if less than 0.
My answer:
#include <iostream>
#include <cmath>
#include<string>
using namespace std;
int count_matches(const string arr[], int size, string query){
int i = 0;
int numMatches;
for (;i<size;i++) {
if (string[i] == (string[i]+1)){
numMatches++;
}
}
return numMatches;
}
int main(){
string selection;
const string array[4]={"dog", "cat", "dog", "dog"};
cout<<"which animal do you want?"<<endl;
cin>> selection;
cout<< "there are " << count_matches(array, 4, selection)<< " matches"<<endl;
return 0;
}
What is wrong?
int count_matches(const string arr[], int size, string query){
int numMatches(0);
for (int i=0; i<size; ++i)
{
if (arr[i] == string)
{
++numMatches;
}
}
return numMatches;
}
This should be a solution to your problem but you will never learn anything from gaining the answer this way. I'd advise reading this tutorial on arrays and loops to better understand how to tackle the problem next time.
Once you get your code to compile, you need to look carefully at this block:
if (string[i] == (string[i]+1)) {
numMatches++;
}
What do you actually want to compare here? string is a type. Take another look at the arguments that you pass into the function and that should make it clear.
Then, once you have a match, you increment numMatches. But what value does this have to start with? What value should it have to start with?
Note that std::count() does exactly what your count_matches() function should do:
std::count(array, array + 4, selection)
This will probably not statisfy whomever marks your homework, but it is worth playing with and learning if you want to advance your C++ skills.
Good luck!

Finding all occurrences of a character in a string

I have comma delimited strings I need to pull values from. The problem is these strings will never be a fixed size. So I decided to iterate through the groups of commas and read what is in between. In order to do that I made a function that returns every occurrence's position in a sample string.
Is this a smart way to do it? Is this considered bad code?
#include <string>
#include <iostream>
#include <vector>
#include <Windows.h>
using namespace std;
vector<int> findLocation(string sample, char findIt);
int main()
{
string test = "19,,112456.0,a,34656";
char findIt = ',';
vector<int> results = findLocation(test,findIt);
return 0;
}
vector<int> findLocation(string sample, char findIt)
{
vector<int> characterLocations;
for(int i =0; i < sample.size(); i++)
if(sample[i] == findIt)
characterLocations.push_back(sample[i]);
return characterLocations;
}
vector<int> findLocation(string sample, char findIt)
{
vector<int> characterLocations;
for(int i =0; i < sample.size(); i++)
if(sample[i] == findIt)
characterLocations.push_back(sample[i]);
return characterLocations;
}
As currently written, this will simply return a vector containing the int representations of the characters themselves, not their positions, which is what you really want, if I read your question correctly.
Replace this line:
characterLocations.push_back(sample[i]);
with this line:
characterLocations.push_back(i);
And that should give you the vector you want.
If I were reviewing this, I would see this and assume that what you're really trying to do is tokenize a string, and there's already good ways to do that.
Best way I've seen to do this is with boost::tokenizer. It lets you specify how the string is delimited and then gives you a nice iterator interface to iterate through each value.
using namespace boost;
string sample = "Hello,My,Name,Is,Doug";
escaped_list_seperator<char> sep("" /*escape char*/, ","/*seperator*/, "" /*quotes*/)
tokenizer<escaped_list_seperator<char> > myTokens(sample, sep)
//iterate through the contents
for (tokenizer<escaped_list_seperator<char>>::iterator iter = myTokens.begin();
iter != myTokens.end();
++iter)
{
std::cout << *iter << std::endl;
}
Output:
Hello
My
Name
Is
Doug
Edit If you don't want a dependency on boost, you can also use getline with an istringstream as in this answer. To copy somewhat from that answer:
std::string str = "Hello,My,Name,Is,Doug";
std::istringstream stream(str);
std::string tok1;
while (stream)
{
std::getline(stream, tok1, ',');
std::cout << tok1 << std::endl;
}
Output:
Hello
My
Name
Is
Doug
This may not be directly what you're asking but I think it gets at your overall problem you're trying to solve.
Looks good to me too, one comment is with the naming of your variables and types. You call the vector you are going to return characterLocations which is of type int when really you are pushing back the character itself (which is type char) not its location. I am not sure what the greater application is for, but I think it would make more sense to pass back the locations. Or do a more cookie cutter string tokenize.
Well if your purpose is to find the indices of occurrences the following code will be more efficient as in c++ giving objects as parameters causes the objects to be copied which is insecure and also less efficient. Especially returning a vector is the worst possible practice in this case that's why giving it as a argument reference will be much better.
#include <string>
#include <iostream>
#include <vector>
#include <Windows.h>
using namespace std;
vector<int> findLocation(string sample, char findIt);
int main()
{
string test = "19,,112456.0,a,34656";
char findIt = ',';
vector<int> results;
findLocation(test,findIt, results);
return 0;
}
void findLocation(const string& sample, const char findIt, vector<int>& resultList)
{
const int sz = sample.size();
for(int i =0; i < sz; i++)
{
if(sample[i] == findIt)
{
resultList.push_back(i);
}
}
}
How smart it is also depends on what you do with those subtstrings delimited with commas. In some cases it may be better (e.g. faster, with smaller memory requirements) to avoid searching and splitting and just parse and process the string at the same time, possibly using a state machine.