Processing strings with toupper() causing an infinite loop - c++

I'm trying to write a program to convert one letter of each word to uppercase. argv[1] is a number like 3. If argv[1] is 3, only the third letter of each word should be uppercase and the others lowercase.
I wrote this disaster of a code, and it's stuck in an infinite loop that only displays the first input char repeatedly.
I need help with the logic.
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int c; // yes, read chars in as ints.
int ncounter = atoi(argv[1]);
int cchecker = 0;
c = cin.get();
while (!cin.eof())
{
if (c == ' ')
{
cchecker = 0;
}
else
{
if (cchecker == ncounter)
{
c = (toupper(c));
cchecker++;
}
else
{
c = (tolower(c));
cchecker++;
}
}
cout.put('\n'); // sometimes this is needed: you'll know when
}
}
Update here's new code, it works almost perfect, except it sometimes doesn't uppercase the first word, kinda strange.
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
int main (int argc, char *argv[])
{
int c ; // yes, read chars in as ints.
int ncounter = atoi(argv[1]);
int cchecker = 0;
c = cin.get() ;
while (!cin.eof())
{
if (c == ' ')
{
cchecker = 0;
cout.put (c);
c = cin.get ();
cchecker++;
}
else
{
if (cchecker == ncounter)
{
cout.put (toupper(c));
c = cin.get() ;
cchecker++;
}
else
{
cout.put (tolower(c));
c = cin.get() ;
cchecker++;
}
}
}
cout.put('\n') ; // sometimes this is needed: you'll know when
}

while (!cin.eof())
Your loop condition states, that the loop ends if eofbit of the standard input stream (represented by the std::cin object) was set in the last iteration. Eofbit would be set upon reading from the standard input when there is no more characters there.
it's stuck in an infinite loop
Your loop never reads from the standard input, and therefore the state of the loop condition can never change. If the loop is entered, it will never stop.

As others have stated, you are reading from std::cin only one time, before entering the loop, so you get stuck in an infinite loop because you never call cin.get() again inside the loop so cin.eof() has a chance to change value. Though, you should consider using while (cin.get(ch)) instead of while (!cin.eof()).
But, why are you reading from std::cin one char at a time to begin with? You say you want to change letters in words, so you should be reading whole words, not individual characters.
Try using operator>> in a loop to read a whole word, replacing the Nth char in that word, eg:
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cctype>
char my_toupper(char ch)
{
return std::toupper(static_cast<unsigned char>(ch));
}
char my_tolower(char ch)
{
return std::tolower(static_cast<unsigned char>(ch));
}
int main(int argc, char *argv[])
{
int ncounter = std::atoi(argv[1]);
std::string word;
while (cin >> word)
{
std::transform(word.begin(), word.end(), word.begin(), my_tolower);
if (word.size() >= ncounter)
word[ncounter-1] = my_toupper(word[ncounter-1]);
std::cout << word << "\n";
}
return 0;
}

Related

C++ - Capitalize the first Character for each word in the given string

I have a char pointer , then i convert it into string format. So i would like to capitalize the first character of each word in this string, I wrote the code below :
#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <time.h>
#include <string>
using namespace std;
void transform(char *s);
int main(int argc, char const *argv[])
{
char *str = new char[255];
strcpy(str, "jimmy catter");
string s;
s+=str; //convert char to string
std::cout<<s<<endl;
for (int i = 0; i < s.length(); ++i)
{
if (s[i] == ' ')
{
if (islower(s[i+1])==1)
{
s[i+1] = toupper(s[i+1]);
}
}
}
std::cout<<s<<endl;
return 0;
}
I would like to the output shoule be "Jimmy Catter" , but the result i got is still in the lower format. Could you please help look with this ?
So basically, there are two things here:
islower() should be treated as if it returns a bool, even if it says it returns an int. This is because for a bool, the actual value is false if 0 and true if any value other than 0. This means that if you wanted to still compare to a numerical value you would say islower(s[i]) != 0 since 1 is not the only valid internal value for true.
For the first character (J), there isn't a space before it. So, what we can do is check the current character is the first character OR if the previous character is space. Basically, instead of checking the current character and changing the next character, we check the previous character (or if it's the first character) and then change the current character.
#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <time.h>
#include <string>
using namespace std;
void transform(char *s);
int main(int argc, char const *argv[])
{
char *str = new char[255];
strcpy(str, "jimmy catter");
string s;
s+=str; //convert char to string
std::cout<<s<<endl;
for (int i = 0; i < s.length(); ++i) {
if (i == 0 || s[i - 1] == ' ') {
if (islower(s[i])) {
s[i] = toupper(s[i]);
}
}
}
std::cout<<s<<endl;
return 0;
}
First thing to note here is that islower returns non zero(>0) number if argument is lowercase instead of 1.
Second you are trying to capitalize char by checking if char before it was whitespace. Nothing wrong with this approach but it won't work on first character so you can do it by adding an extra line before the loop. So with some tweaking it works fine now:
#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <time.h>
#include <string>
using namespace std;
// void transform(char *s);
int main(int argc, char const *argv[])
{
string s = "jimmy catter ";
/*
char *str = new char[255];
strcpy(str, "jimmy catter");
string s;
s+=str; //convert char to string
*/
std::cout<<s<<endl;
s[0]=toupper(s[0]);
for (int i = 0; i < s.length()-1; ++i)
{
if (s[i] == ' ')
{
if (islower(s[i+1])>=1)
{
s[i+1] = toupper(s[i+1]);
}
}
}
std::cout<<s<<endl;
return 0;
}
You may use ASCII notations because they are quite clear to understand and execute in such programs.
I modified your code a little bit in the loop part and it gives correct output. Have a look at it.
for (int i = 0; i < s.length(); ++i)
{
if(!i&&97<=s[i]<=122) //handles border condition where first letter is small case
{
s[i] = s[i]-32;
}
if ((i!=s.length-1)&&s[i] == ' ') //prevents invalid output where last character is a space
{
if (97<=s[i+1]<=122) //checks if letter after space is small case
{
s[i+1] = s[i+1]-32;
}
}
}
std::cout<<s<<endl;
return 0;
}

My c++ loop doesn't stop when i tell it to do it through the console

I have made a loop which should encrypt the phrases I tell it to, but didn't finish because of the problem. It should detect when I say "stop" in the console and shut down the loop. It doesn't work.
What i want it to do is to detect if i said stop and break the loop. I shouldn t get any random missfires from getting the letters s t o p from other words. As you can see, every time there is a letter out of order, it resets the vectors which locks all of the ifs until 'c' gets the correct letters in the correct order.
using namespace std;
int main()
{
char c,v[5];
int i=0;
while(i!=1)
{
cin.get(c);
if(c=='s' or v[1]=='s')
{
v[1]='s';
if(c=='t' or v[2]=='t')
{
v[2]='t';
if(c=='o' or v[3]=='o')
{
v[3]='o';
if(c=='p' or v[4]=='p')
{
v[4]='p';
v[1]=v[2]=v[3]=v[4]=0;
i=1;
}
else
v[1]=v[2]=v[3]=0;
}
else
v[1]=v[2]=0;
}
else
v[1]=0;
}
cout<<c;
if (i==1)
break;
}
return 0;
}
That should the work and is not indented hell code. It assumes that you are entering one character at a time.
#include <iostream>
int main(int argc, char const *argv[])
{
char keyword[] = "stop";
char* matching_char = keyword;
char char_from_user;
while(*matching_char != '\0')
{
std::cin.get(char_from_user);
// Reset if different character
if(*matching_char != char_from_user)
matching_char = keyword;
// Increment position of match
if(*matching_char == char_from_user)
++matching_char;
// Ignore rest in buffer
std::cin.ignore();
}
return 0;
}
Following your logic, you just need to assign the v array values after each if/else condition otherwise it will just get immediately reassigned to 0. For example, you first assign v[1] = 's', and then right after you assign it to v[1] = 0, because the if returns false in first iteration. The following code should solve the problem.
#include <iostream>
using namespace std;
int main()
{
char c,v[5];
int i=0;
while(i!=1)
{
cin.get(c);
if(c=='s' || v[1]=='s')
{
if(c=='t' || v[2]=='t')
{
if(c=='o' || v[3]=='o')
{
if(c=='p' || v[4]=='p')
{
v[4]='p';
v[1]=v[2]=v[3]=v[4]=0;
i=1;
}
else
v[1]=v[2]=v[3]=0;
v[3]='o';
}
else
v[1]=v[2]=0;
v[2]='t';
}
else
v[1]=0;
v[1]='s';
}
if (i==1)
break;
}
return 0;
}

f.getline() iterator not increasing

I don't understand why my iterator(nr) doesn't increase.
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <string.h>
using namespace std;
ifstream f("date.in");
ofstream g("date.out");
int main()
{
int l, nr = 0;
char x, s[100];
f >> l;
while(!f.eof())
{
f.getline(s, 100);
{
g << s;
nr++;
}
if(nr == 19)
{
g << '\n';
nr = 0;
}
}
return 0;
}
I expect to get the output to start on a new line every 20 characters.
The problem is that you read and count complete lines as #Andrey Akhmetov said in the comments. If you want to inject a \n every 20 chars, the easiest way would be to read one character at a time:
void add_newlines(std::istream& in, std::ostream& out) {
char ch;
int nr = 0;
// Read one char with "<istream>.get()". The returned file descriptor (in) will
// be true or false in a boolean context (the while(<condition>)) depending on
// the state of the stream. If it fails extracting a character, the failbit will
// be set on the stream and "in" will be "false" in the boolean context and
// the while loop will end.
while( in.get((ch)) ) {
out.put(ch);
if(++nr == 19) {
out << '\n';
nr = 0;
}
}
}
Call it with add_newlines(f, g);.
Note that get() and put() use Unformatted I/O while the out << '\n' uses Formatted output and will widen() \n to \r\n on Windows which probably could cause sequences like \r\r\n\n to appear in your output (if you run on Windows).

segmentation fault(core dumped) in C dealing with getchar

I try to read a formula full of -,(,),|,&,>,= characters. I want to skip the blanks and end-of-line characters and put the others in an array to use them efficiently.
The code is:
int main()
{
char *array;
int i=0,j;
char c=getchar();
array=(char*)malloc(sizeof(char));
while (c != EOF)
{
if( islower(c) || (c!=' ' && c!='\n'))
{
array[i]=c;
i++;
array=(char*)realloc(array,sizeof(char)*(i+1));
}
}
}
My input is:
-(-(a&k) > ( -((a|-k)
|c ))
but it gives me segmentation fault. What should I do?
The problem is that you are managing memory yourself and that you are never changing the value of c which, if it's originally different from EOF, will cause an infinite loop. Use std::string:
int main() {
std::string array;
char c = getchar();
while (c != EOF) {
if(islower(c) || (c!=' ' && c!='\n'))
array.push_back(c);
c = getchar();
}
}
Live demo
Not only this is easier to read and to write, but it is also much more efficient than keep reallocating memory at every loop.
for C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(){
char *array;
int ch, i=0, capacity = 16;
array = malloc(capacity);
while(EOF!=(ch = getchar())){//It is necessary to receive an int return value is in order to properly compare EOF.
if(!isspace(ch)){//islower not necessary when OR(||) condition
array[i++]=ch;
if(i==capacity)//Efficiency is not good of character by character
array = realloc(array, capacity += 16);
}
}
array[i] = '\0';
printf("%s\n", array);
free(array);
return 0;
}

end of istream not detected when expected

I wrote a function to count vowels. If there is a vowel at the end of the stream it gets counted twice. Why?
#include <iostream>
#include <string>
#include <map>
using namespace std;
void countChars(istream& in, string theChars, ostream& out) {
map<char, int> charMap;
map<char, int>::iterator mapIt;
for (string::iterator i = theChars.begin(); i != theChars.end(); ++i) {
charMap[*i] = 0;
}
while (in) {
char c;
in >> c;
c = tolower(c);
if (charMap.count(c))
++charMap[c];
}
for (mapIt = charMap.begin(); mapIt != charMap.end(); ++mapIt) {
out << (*mapIt).first << ":" << (*mapIt).second << endl;
}
}
int main(int argc, char **argv) {
std::string s = "aeiou";
countChars(std::cin, s, std::cout);
}
Because in evaluates as false when the last read failed due to running out of data, not because the next read would fail due to running out of data. It doesn't "look ahead", it only knows that the stream is finished if it has previously tried and failed to read.
So the following happens:
last char is read and processed
in evaluates as true, so the loop repeats
you try to read again, but there is no more data, so c is not modified
by undefined (although unsurprising) behavior, c happens to contain the value it had in the last run of the loop
hence, you process the same char again.
You should write:
char c;
while (in >> c) { etc }