The following code is supposed to make the first character uppercase, as well as any other occurrences of that same character.
For example, if the input is "complication", the output should be "CompliCation". But the output is "Complication" instead.
#include <cctype>
#include <iostream>
#include <string>
int main()
{
std::string cadena;
std::cout << "Write a word: ";
std::cin >> word;
for (int i = 0; i < word.length(); i++)
{
if (word[0] == word[i])
word[i] = std::toupper(word[i]);
}
std::cout << word<< '\n';
}
What is wrong with my code?
By the time you compare the second c, the first c has been converted to C. Hence, Cadena[0] == Cadena[i] is false.
Store the first character first and then compare it with the characters of the string.
char c = Cadena[0];
for (i = 0; i < Cadena.length(); i++)
{
if (c == Cadena[i])
Cadena[i] = toupper(Cadena[i]);
}
You can even pre-compute the uppercase character and use it in the loop.
char c = Cadena[0];
char upperC = toupper(c);
for (i = 0; i < Cadena.length(); i++)
{
if (c == Cadena[i])
Cadena[i] = upperC;
}
Because you make the first character upper case, so the 7th character does not match any more.
Modify your loop like this instead.
char c = Cadena[0];
for (i = 0; i < Cadena.length(); i++)
{
if (Cadena[i] == c)
Cadena[i] = toupper(Cadena[i]);
}
After the first loop Cadena[0] = 'C' so when you encounter another occurrence of this letter, you do the test : if ('C' == 'c') which results to false.
You should first capitalize the characters that are the same to the first character (start your loop at i=1), then capitalize the first character after your for loop.
Because once you apply toupper on the very first character it becomes upper case. Then when it is compared with the same character but lowcase, the comparison returns false. Because 'C' is not the same as 'c'.
Related
I am trying to get the number of words from a line in a text file. I used .getline() in order to extract a line from the entire text file. The code is:
#include <iostream>
#include <iomanip>
#include <fstream>
int main()
{
char const* filename = "duck.txt";
std::ifstream ifs{ filename };
constexpr size_t MAX_LINE_LEN{ 2048 };
char line[MAX_LINE_LEN];
int lineCount = 0;
int totalWordCount = 0;
int totalByteCount = 0;
while (ifs.getline(line, MAX_LINE_LEN-1))
{
int lineWord = 0;
char* q = &line[0];
if (ifs.eof())
{
lineCount--;
totalByteCount--;
}
while (*q != '\0')
{
q++;
totalByteCount++;
}
totalByteCount++;
if (*q == '\0')
{
lineCount++;
}
int i = 0;
int j = 0;
while (line[i] != '\0' && line[j] != '\0')
{
while (line[i] == ' ')
{
i++;
}
j = i;
while (line[j] != ' ')
{
j++;
}
lineWord++;
j = i;
}
totalWordCount += lineWord;
}
std::cout << "Total Lines: " << lineCount << '\n' << "Total Words: " << totalWordCount << '\n' << "Total Bytes: " << totalByteCount;
}
But the only important part is:
int i = 0;
int j = 0;
while (line[i] != '\0' && line[j] != '\0')
{
while (line[i] == ' ')
{
i++;
}
j = i;
while (line[j] != ' ')
{
j++;
}
lineWord++;
j = i;
}
totalWordCount += lineWord;
I'm trying to read the line character by character until I reach a non-whitespace character after which I'll assign that subscript to i. Then, I'll set j to the subscript of the first whitespace encountered after the character of line[i]. If j finds a whitespace, then there is a word. If j reaches '\0', then the line has ended and I end the while loop. When I try to compile and run this, the compiler just displays nothing. What am I doing wrong? Also, I can't add anymore header files
In your original code:
int i = 0;
int j = 0;
while (line[i] != '\0' && line[j] != '\0')
{
while (line[i] == ' ') // you do not check for end of string character?
{
i++;
}
j = i; // here i = j = beginning of word.
// since you rewind to beginning of the word below,
// your program keeps repeating this loop endlessly
while (line[j] != ' ') // this loop could easily run for quite a while.
// until it seg-faults
{
j++;
}
lineWord++;
j = i; // BUG Here! you're 'rewinding' j to to beginning of the word.
// you loop back and keep counting the same word over and over.
}
totalWordCount += lineWord;
What is the purpose of i and j ? Wouldn't the code be simpler and easier to read and maintain using a single pointer? Or a single index? This kind of algorithm is where a pointer would excel, though, as the only arithmetic pointer operation needed is increment.
As in:
const char* p = &line[0];
int word_count = 0;
line[MAX_LINE_LEN - 1] = 0; // making sure the code below stays within boundaries.
for(;;)
{
// skip to next word
while (*p && *p == ' ') ++p; // stay within the string by testing for zero.
if (!*p)
break; // done!
// since p now points to the beginning of a word, we've got one
++word_count;
// skip to end of word
while (*p && *p != ' ') ++p;
}
This is all fine, for most cases but there could be some exceptional typos in the text, like "hello, world !", where the last punctuation would be counted as a word. There is also the problem of horizontal tabs, which could also be counted erroneously as words.
To cover these cases, you should test for valid characters for words, instead of for space, which is a rather vague concept.
Without using library calls, You'd need to define what constitutes spaces and punctuation, either with a constant, or with a function.
Substituting the test for space with a more targeted test, using isalnum() to check for alpha or numeric characters:
for(;;)
{
// skip to next word
while (*p && !std::isalnum(*p & 0xFF)) ++p;
if (!*p)
break; // done!
++word_count;
// skip to end of word
while (*p && std::isalnum(*p & 0xFF)) ++p;
}
Beware of function of the isalnum(), isalpha().. family, they define their input as an int, the mask ensures that characters in the 128-255 range are not sign-extended aand are passed correctly as positive values.
/* I have written a code for a simple hangman based on instructions given, I just want to know how to detect the duplicated inputs. For this code, It only detects correct letters and the length
For example:
user input: HAM
H
A
A
HANGMAN! */
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
// Word to be guessed can be assumed to be at most 20 characters long (including end-of-string null character)
char HangmanWord[20];
// Variable to store current guess
char GuessLetter;
int count = 0;
std::cin >> HangmanWord;
//char guessedletter[strlen(HangmanWord)];
//int j = 0;
bool valid = true;
// Check that input word only consists of uppercase English letters
for (int i = 0; i < strlen(HangmanWord); i++)
{
if ((HangmanWord[i] > 'Z') || (HangmanWord[i] < 'A'))
{
valid = false;
break;
}
}
while (valid == true)
{
std::cin >> GuessLetter; //Takes the Guess letter
if ((GuessLetter > 'Z') || (GuessLetter < 'A')) //Check that guessed letter is uppercase
{
break;
}
else
{
for (int i = 0; i < strlen(HangmanWord); i++) //loop to check every letter in word
{
if (GuessLetter == HangmanWord[i]) { //if the letter is equal to any letter in the word the count increases
count++;
break;
}
if (i == strlen(HangmanWord) - 1) { //If no letter is equal to any letter in the word the program exits
valid = false;
}
}
if (count == strlen(HangmanWord)) { //Checks if all letters were guessed and exits the loop after
valid = false;
}
}
}
if (count == strlen(HangmanWord)) { //Checks if all letters were guessed correct to print Hangman
cout << "HANGMAN!\n";
valid = false;
}
If you want to detect whether a letter has already been input, you can work with ASCII characters being represented by numbers. Assuming we limit ourselves to uppercase letters, 'A' is 65 and 'Z' is 90.
We can do math with these. 'A' - 'A' is 0 and 'C' - 'A' is 2.
We also know that arrays are indexed starting from zero.
We can put these things together to create an array of boolean values, and flag them as letters are guessed.
std::array<std::bool, 26> already_guessed;
std::fill(already_guess.begin(), already_guessed.end(), false);
And we can then check on whether a letter has been guessed by looking it up. Consider, for instance, checking whether 'D' has been guessed. They should start out false, as nothing has been guessed at the beginning.
already_guessed['D' - 'A']
If it hasn't, we can mark it as guessed:
already_guessed['D' - 'A'] = true
I have an array of strings, I want to check whether the first characters of all the strings are the same or not.
I know how to retrieve the first character of a string, by this method
char first_letter;
first_letter = (*str)[0];
Initially, I thought to go the brute force way, by checking for the first letter for every strings, using a nested for loop.
int flag = 0
char f1,f2;
for(int i = 0;i < size_arr - 1;i++){
f1 = (*str[i])[0];
for(int j = i + 1;j < size_arr;j++){
f2 = (*str[j])[0];
if(f1 != f2)
flag += 1;
}
}
if(!(flag))
cout<<"All first characters same";
else
cout<<"Different";
But I need an approach to find whether the first letters of all the strings present in an array are the same or not. Is there any efficient way?
You needn't use a nested for loop.Rather modify your code this way
for(int i = 0;i < size_arr - 2;i++){
f1 = (*str[i])[0];
f2 = (*str[i+1])[0];
if( f1!=f2 ){
printf("not same characters at first position");
break;
flag=1;
}
}
if(flag==0)printf("same characters at first position");
I made this C approach for you (it's because you have used character arrays here, not std::string of C++ – so it's convenient to describe using C code):
#include <stdio.h>
#define MAX_LENGTH 128
int main(void) {
char string[][MAX_LENGTH] = {"This is string ONE.", "This one is TWO.",
"This is the third one."};
char first_letter = string[0][0];
int total_strs = sizeof(string) / sizeof(string[0]);
int FLAG = 1;
// Iterate through each letter of each string
for (int i = 0; i < total_strs; i++)
// First letter of the string is equal to first_letter?
if (string[i][0] != first_letter) {
FLAG = 0; // set to 0 as soon as it finds
break; // the initial_letter is NOT equal to the first
} // letter
if (FLAG)
fprintf(stdout, "The strings have the same initial letters.\n");
else
fprintf(stdout, "Not all strings have the same initial letters.\n");
return 0;
}
If you want to convert it to a C++ code, no big issue – just replace stdio.h with iostream, int FLAG = 1 with bool FLAG = true, fprintf() to std::cout statements, that's it.
In case you need to work with std::string for the same job, just simply get the array of those strings, set the flag as true by default, iterate through each string, and match in case the first string's initial letter is equivalent to others, eventually, mark the flag as false in as soon as a defected string is found.
The program will display (if same initial vs. if not):
The strings have the same initial letters.
Not all strings have the same initial letters.
The below program is intended to make all characters in a string lowercase, remove all vowels, and then print a full stop before every letter. For example, an input of "umbrella" would become ".m.b.r.l.l". But when I input "tour", the 'u' is not removed.
char ChangeToLow(char letter) {
if(letter <= 'Z' && letter >= 'A')
return letter - ('A' - 'a');
return letter;
}
int main()
{
string name;
cin>>name;
for (int i = 0 ; i < name.length() ; i++)
{
name[i] = ChangeToLow(name[i]);
if (name[i] == 'y' || name[i] == 'a'|| name[i] == 'u'|| name[i] == 'i'|| name[i] == 'e'|| name[i] == 'o')
{
name.erase(i,1);
}
}
for (int i = 0 ; i < name.length() ; i++)
{
cout<<'.'<<name[i];
}
}
I expect the output ".t.r" but instead it prints ".t.u.r".
Thanks in advance.
When you erase a character from the string, the remaining contents move over to fill the space. Their indexes adjust accordingly. With your tour example, it'll look something like the following:
Your loop counter, i, was incremented to 2 after you deleted the 'o' from tour, and name[i] is now 'r'. One option to avoid this behavior is to decrement i when you delete a vowel.
I have some suggestion for you. Firstly you shouldn't put using namespace std; in your code. It just adds confusion and is considered a bad practice. I think it would be also a good thing, if you would consider to learn the STL, if it is really your aim to learn C++ in depths. As for the error I think that the already posted answer shows your wrong assumptions.
#include <iostream>
#include <cstdlib>
#include <locale>
#include <set>
#include <algorithm>
int main()
{
std::string name;
std::cin>>name;
std::set<char> vowels={'a','u','i','e','o'};
std::transform(name.begin(), name.end(), name.begin(), [](auto v){ return std::tolower(v, std::locale());});
auto iter=std::remove_if(name.begin(), name.end(), [&vowels](auto v){ return vowels.find(v)!=vowels.end();});
name.erase(iter,name.end());
for (int i = 0 ; i < name.length() ; i++)
{
std::cout<<'.'<<name[i];
}
return EXIT_SUCCESS;
}
Below is an example code that is not working the way I want.
#include <iostream>
using namespace std;
int main()
{
char testArray[] = "1 test";
int numReplace = 2;
testArray[0] = (int)numReplace;
cout<< testArray<<endl; //output is "? test" I wanted it 2, not a '?' there
//I was trying different things and hoping (int) helped
testArray[0] = '2';
cout<<testArray<<endl;//"2 test" which is what I want, but it was hardcoded in
//Is there a way to do it based on a variable?
return 0;
}
In a string with characters and integers, how do you go about replacing numbers? And when implementing this, is it different between doing it in C and C++?
If numReplace will be in range [0,9] you can do :-
testArray[0] = numReplace + '0';
If numReplace is outside [0,9] you need to
a) convert numReplace into string equivalent
b) code a function to replace a part of string by another evaluated in (a)
Ref: Best way to replace a part of string by another in c and other relevant post on SO
Also, since this is C++ code, you might consider using std::string, here replacement, number to string conversion, etc are much simpler.
You should look over the ASCII table over here: http://www.asciitable.com/
It's very comfortable - always look on the Decimal column for the ASCII value you're using.
In the line: TestArray[0] = (int)numreplace; You've actually put in the first spot the character with the decimal ASCII value of 2. numReplace + '0' could do the trick :)
About the C/C++ question, it is the same in both and about the characters and integers...
You should look for your number start and ending.
You should make a loop that'll look like this:
int temp = 0, numberLen, i, j, isOk = 1, isOk2 = 1, from, to, num;
char str[] = "asd 12983 asd";//will be added 1 to.
char *nstr;
for(i = 0 ; i < strlen(str) && isOk ; i++)
{
if(str[i] >= '0' && str[i] <= '9')
{
from = i;
for(j = i ; j < strlen(str) && isOk2)
{
if(str[j] < '0' || str[j] > '9')//not a number;
{
to=j-1;
isOk2 = 0;
}
}
isOk = 0; //for the loop to stop.
}
}
numberLen = to-from+1;
nstr = malloc(sizeof(char)*numberLen);//creating a string with the length of the number.
for(i = from ; i <= to ; i++)
{
nstr[i-from] = str[i];
}
/*nstr now contains the number*/
num = atoi(numstr);
num++; //adding - we wanted to have the number+1 in string.
itoa(num, nstr, 10);//putting num into nstr
for(i = from ; i <= to ; i++)
{
str[i] = nstr[i-from];
}
/*Now the string will contain "asd 12984 asd"*/
By the way, the most efficient way would probably be just looking for the last digit and add 1 to it's value (ASCII again) as the numbers in ASCII are following each other - '0'=48, '1'=49 and so on. But I just showed you how to treat them as numbers and work with them as integers and so. Hope it helped :)