Lowercasing Capital Letters in char array[] in C++ through Pointers - c++

I am trying to use pointers to recursively lowercase all capital letters
using the C++ programming language. Below is the code snippet:
// Example program
#include <iostream>
#include <string>
using namespace std;
void all_lower(char* input) {
if ( *input ) {
cout << input << endl;
return;
}
if ( *input >= 'A' && *input <= 'Z') {
*input += 32; // convert capital letter to lowercase
}
cout << *input << endl;
all_lower(++input); // simply move to next char in array
}
int main() {
char test[] = "Test";
all_lower(test);
return 0;
}
The output ends up being:
"Test"
even though I tried to increase the ASCII code value of the element by 32.

You are exiting the function on the first non-null character detected, which is 'T', and then you output the entire array before exiting, so you are seeing the original unmodified input. You are not recursing through the array at all. You need to recurse through the array until you reach the null terminator.
You need to change this:
if ( *input ) {
cout << input << endl;
return;
}
To this instead:
if ( *input == 0 ) {
return;
}
Then the function will work as expected.
That being said, I suggest you remove the cout statements from the function, and do a single cout in main() after the function has exited. This will speed up the function, and prove that the content of the test[] array is actually being modified:
#include <iostream>
using namespace std;
void all_lower(char* input)
{
if ( *input == 0 ) {
return;
}
if ( *input >= 'A' && *input <= 'Z') {
*input += 32; // convert capital letter to lowercase
}
all_lower(++input); // simply move to next char in array
}
int main()
{
char test[] = "TEST";
cout << "Before: " << test << endl;
all_lower(test);
cout << "After: " << test << endl;
return 0;
}
Live Demo
And, since you are using C++, consider removing all_lower() altogether and use the STL std::transform() algorithm instead:
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
char test[] = "TEST";
cout << "Before: " << test << endl;
transform(test, test+4, test, [](char ch){ return tolower(ch); });
cout << "After: " << test << endl;
return 0;
}
Live Demo

Something short and easy:
#include <iostream>
#include <string>
using namespace std;
void all_lower(const char* input) {
if (!*input) {
std::cout << std::endl;
return;
}
std::cout << (char)(std::isalpha(*input) ? tolower(*input) : *input);
all_lower(++input); // simply move to next char in array
}
int main() {
all_lower("Test");
return 0;
}

Related

Having trouble with std::string::compare() return values in c++

Relatively new to c++.
Having trouble understanding an issue I am having with the compare() function returning 1 instead of 0.
I have a program which reads a text file containing an arbitrary number of questions and answers for a quiz. It is formatted as such:
Q: How many days in a week?
A: seven
I have three files, main.cpp, Quiz.cpp, and Quiz.h:
main.cpp:
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
#include <ctime>
#include <cstdlib>
#include "Quiz.h"
using namespace std;
int main(int argc, char* argv[]){
srand(unsigned(time(0)));
vector<Quiz> quizVector;
ifstream inputQuiz;
inputQuiz.open(argv[1]);
string q, a;
int questionCount = 0;
if(inputQuiz.is_open()){
getline(inputQuiz, q);
getline(inputQuiz, a);
while(!inputQuiz.eof()){
Quiz *instance = new Quiz(q, a);
quizVector.push_back(*instance);
questionCount++;
getline(inputQuiz, q);
getline(inputQuiz, a);
}
}
random_shuffle(quizVector.begin(), quizVector.end());
string userInput;
for(int i = 0; i < questionCount; i++){
cout << quizVector[i].getQuestion() << endl;
cout << "A: ";
getline(cin, userInput);
if(quizVector[i].getAnswer().compare("A: " + userInput) == 0){
cout << "Correct." << endl;
}
else{
cout << "Incorrect." << endl;
}
}
return 0;
}
Quiz.cpp:
#include <string>
#include "Quiz.h"
int Quiz::score = 0;
std::string Quiz::getQuestion(){
return question;
}
std::string Quiz::getAnswer(){
return answer;
}
Quiz.h:
#ifndef QUIZ_H
#define QUIZ_H
class Quiz{
private:
std::string question {""};
std::string answer {""};
public:
Quiz() = default;
Quiz(std::string q, std::string a) : question {q}, answer {a} {}
std::string getQuestion();
std::string getAnswer();
};
#endif
My problem lies within main.cpp:
for(int i = 0; i < questionCount; i++){
cout << quizVector[i].getQuestion() << endl;
cout << "A: ";
getline(cin, userInput);
if(quizVector[i].getAnswer().compare("A: " + userInput) == 0){
cout << "Correct." << endl;
}
else{
cout << "Incorrect." << endl;
}
}
When I input the correct answer corresponding to each question, compare() does not return 0, but consistently returns 1. There are no leading or trailing spaces at the start or ends of each line in the text file. Am I misunderstanding how getline() or compare() works? Is it something else? Any help is appreciated!
I see a number of problems with this code:
std::random_shuffle() is deprecated in C++14 and removed in C++17, use std::shuffle() instead.
you are not validating that argv contains an input parameter before using it.
Your use of eof() in the while loop is wrong. For instance, if the last question/answer pair in the file is terminated by EOF instead of a line break, getline() will still return the question/answer to you, but it will also set the eofbit flag on the stream, which will cause eof() to return true and thus you will skip saving the last pair into the vector. The stream is not technically in a failed state yet in this situation (see the diagram at https://en.cppreference.com/w/cpp/io/basic_ios/eof), so you shouldn't skip the last pair if it terminates with EOF rather than a line break.
Your while loop is leaking memory.
you don't need questionCount at all, use quizVector.size() instead. Or better, a range-for loop.
you don't really need to use compare() at all, you can use operator== instead. But, if you do use compare(), you should take into account that it is case-sensitive (as is operator==). You should also take advantage of the fact that compare() lets you specify an index to start comparing from, so you can ignore the A: prefix in the stored answer (alternatively, you could just strip off the Q: and A: prefixes when storing the question/answer in Quiz's constructor). Otherwise, you can use your compiler's strcmpi() function instead (if it offers one).
Try something more like this instead:
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
#include <random>
#include <cctype>
#include "Quiz.h"
using namespace std;
string toLowercase(string s) {
transform(s.begin(), s.end(), s.begin(),
[](unsigned char c){ return tolower(c); }
);
return s;
}
int main(int argc, char* argv[]){
if (argc < 2){
cerr << "Please specify a file to open!" << endl;
return 0;
}
ifstream inputQuiz(argv[1]);
if (!inputQuiz.is_open()) {
cerr << "Can't open the file!" << endl;
return 0;
}
vector<Quiz> quizVector;
string q, a, userInput;
while (getline(inputQuiz, q) && getline(inputQuiz, a)) {
quizVector.emplace_back(q, a);
}
random_device rd;
mt19937 g(rd());
shuffle(quizVector.begin(), quizVector.end(), g);
for(auto &quiz : quizVector){
cout << quiz.getQuestion() << endl;
cout << "A: ";
getline(cin, userInput);
userInput = toLowercase(userInput);
a = toLowercase(quiz.getAnswer());
if (a == ("a: " + userInput)) {
// or:
// if (a.compare(2, string::npos, userInput) == 0) {
// or, if you strip off "A:" beforehand:
// if (a == userInput) {
cout << "Correct." << endl;
}
else {
cout << "Incorrect." << endl;
}
}
return 0;
}

How do I remove repeated words from a string and only show it once with their wordcount

Basically, I have to show each word with their count but repeated words show up again in my program.
How do I remove them by using loops or should I use 2d arrays to store both the word and count?
#include <iostream>
#include <stdio.h>
#include <iomanip>
#include <cstring>
#include <conio.h>
#include <time.h>
using namespace std;
char* getstring();
void xyz(char*);
void tokenizing(char*);
int main()
{
char* pa = getstring();
xyz(pa);
tokenizing(pa);
_getch();
}
char* getstring()
{
static char pa[100];
cout << "Enter a paragraph: " << endl;
cin.getline(pa, 1000, '#');
return pa;
}
void xyz(char* pa)
{
cout << pa << endl;
}
void tokenizing(char* pa)
{
char sepa[] = " ,.\n\t";
char* token;
char* nexttoken;
int size = strlen(pa);
token = strtok_s(pa, sepa, &nexttoken);
while (token != NULL) {
int wordcount = 0;
if (token != NULL) {
int sizex = strlen(token);
//char** fin;
int j;
for (int i = 0; i <= size; i++) {
for (j = 0; j < sizex; j++) {
if (pa[i + j] != token[j]) {
break;
}
}
if (j == sizex) {
wordcount++;
}
}
//for (int w = 0; w < size; w++)
//fin[w] = token;
//cout << fin[w];
cout << token;
cout << " " << wordcount << "\n";
}
token = strtok_s(NULL, sepa, &nexttoken);
}
}
This is the output I get:
I want to show, for example, the word "i" once with its count of 5, and then not show it again.
First of all, since you are using c++, I would recommend you to split text in c++ way(some examples are here), and store every word in map or unordered_map. Example of my realization you can find here
But if you don't want to rewrite your code, you can simply add a variable that will indicate whether a copy of the word was found before or after the word position. If a copy was not found in front, then print your word
This post gives an example to save each word from your 'strtok' function into a vector of string. Then, use string.compare to have each word compared with word[0]. Those indexes match with word[0] are marked in an int array 'used'. The count of match equals to the number marks in the array used ('nused'). Those words of marked are then removed from the vector, and the remaining carries on to the next comparing process. The program ends when no word remained.
You may write a word comparing function to replace 'str.compare(str2)', if you prefer not to use std::vector and std::string.
#include <iostream>
#include <string>
#include <vector>
#include<iomanip>
#include<cstring>
using namespace std;
char* getstring();
void xyz(char*);
void tokenizing(char*);
int main()
{
char* pa = getstring();
xyz(pa);
tokenizing(pa);
}
char* getstring()
{
static char pa[100] = "this is a test and is a test and is test.";
return pa;
}
void xyz(char* pa)
{
cout << pa << endl;
}
void tokenizing(char* pa)
{
char sepa[] = " ,.\n\t";
char* token;
char* nexttoken;
std::vector<std::string> word;
int used[64];
std::string tok;
int nword = 0, nsize, nused;
int size = strlen(pa);
token = strtok_s(pa, sepa, &nexttoken);
while (token)
{
word.push_back(token);
++nword;
token = strtok_s(NULL, sepa, &nexttoken);
}
for (int i = 0; i<nword; i++) std::cout << word[i] << std::endl;
std::cout << "total " << nword << " words.\n" << std::endl;
nsize = nword;
while (nsize > 0)
{
nused = 0;
tok = word[0] ;
used[nused++] = 0;
for (int i=1; i<nsize; i++)
{
if ( tok.compare(word[i]) == 0 )
{
used[nused++] = i; }
}
std::cout << tok << " : " << nused << std::endl;
for (int i=nused-1; i>=0; --i)
{
for (int j=used[i]; j<(nsize+i-nused); j++) word[j] = word[j+1];
}
nsize -= nused;
}
}
Notice that the removal of used words has to do in backward order. If you do it in sequential order, the marked indexes in the 'used' array will need to be changed. A running test:
$ ./a.out
this is a test and is a test and is test.
this
is
a
test
and
is
a
test
and
is
test
total 11 words.
this : 1
is : 3
a : 2
test : 3
and : 2
I read your last comment.
But I am very sorry, I do not know C. So, I will answer in C++.
But anyway, I will answer with the C++ standard approach. That is usually only 10 lines of code . . .
#include <iostream>
#include <algorithm>
#include <map>
#include <string>
#include <regex>
// Regex Helpers
// Regex to find a word
static const std::regex reWord{ R"(\w+)" };
// Result of search for one word in the string
static std::smatch smWord;
int main() {
std::cout << "\nPlease enter text: \n";
if (std::string line; std::getline(std::cin, line)) {
// Words and its appearance count
std::map<std::string, int> words{};
// Count the words
for (std::string s{ line }; std::regex_search(s, smWord, reWord); s = smWord.suffix())
words[smWord[0]]++;
// Show result
for (const auto& [word, count] : words) std::cout << word << "\t\t--> " << count << '\n';
}
return 0;
}

Reversing the Character Case of a string

I'm stuck on a particular problem. I'm trying to take a string, and reverse the character cases in the string.
For Example: "HaVinG FuN" should flip to "hAvINg fUn."
I think it has something to do with my loop or my If/Else statements. What am I missing? All capitalized characters come out capitalized still. All lower case characters also come out capitalized as well... My other two functions are behaving correctly, but not my reverseFunct function... FYI I've omitted the other functions to try to cut-down on clutter and focus on my problem.
#include "stdafx.h"
#include <string>
#include <iostream>
#include <cctype>
#include <cstring>
using namespace std;
// Function Prototypes
void upperFunct(char *);
void lowerFunct(char *);
void reverseFunct(char *);
int main()
{
cout << "Enter a string: " << endl;
char ltrs [300];
cin.getline(ltrs, 300);
char *ptr = nullptr;
ptr = ltrs;
upperFunct(ptr);
lowerFunct(ptr);
reverseFunct(ptr);
return 0;
}
//----------------------------------//
void upperFunct(char *ltrptr)
{
int count = 0;
while (ltrptr[count] != '\0')
{
ltrptr[count] = toupper(ltrptr[count]);
count++;
}
{
cout << "---> toupper function: " << ltrptr << endl;
}
}
//------------------------------------//
void lowerFunct(char *ltrptr)
{
int count = 0;
while (ltrptr[count] != '\0')
{
ltrptr[count] = tolower(ltrptr[count]);
count++;
}
cout << "---> tolower function: " << ltrptr << endl;
}
//------------------------------------//
void reverseFunct(char *ltrptr) // <-----NOT REVERSING CHARACTERS
{
int count = 0;
while (ltrptr[count] != '\0')
{
if (isupper(ltrptr[count]))
{
ltrptr[count] = tolower(ltrptr[count]);
}
else
{
ltrptr[count] = toupper(ltrptr[count]);
}
count++;
}
cout << "---> reverse function: " << ltrptr << endl;
}
Your check for lowercase letters reads as
else if (islower(ltrptr[count]));
Notice the extra semicolon.
This semicolon terminates the if statement, and thus the succeeding conversion to uppercase is not a then-clause to this if statement but rather is executed unconditionally on every character.
Change like this
// Function Prototypes "HaVinG FuN" should flip to "hAvINg fUn."
void reverseFunct(char *);
int main()
{
//cout << "Enter a string: " << endl;
char ltrs[300] = "HaVinG FuN";
//cin.getline(ltrs, 300);
char *ptr = nullptr;
ptr = ltrs;
reverseFunct(ptr);
ptr = nullptr;
return 0;
}
void reverseFunct(char *ltrptr) // <-----NOT REVERSING CHARACTERS
{
int count = 0;
while (ltrptr[count] != '\0')
{
if (isupper(ltrptr[count]))
{
ltrptr[count] = tolower(ltrptr[count]);
}
else
{
ltrptr[count] = toupper(ltrptr[count]);
}
count++;
}
cout << "---> reverse function: " << ltrptr << endl;
}
You're writing C code. Here's a C++ way to do it:
#include <string>
#include <algorithm>
char reverse_case_char(char c) {
const auto uc = static_cast<unsigned char>(c); // Sic.
return ::isupper(uc)? ::tolower(uc): ::toupper(uc);
}
void reverse_case(std::string& str) {
std::transform(str.begin(), str.end(), str.begin(), reverse_case_char);
}
#include <cassert>
int main()
{
std::string fun = "HaVinG FuN";
reverse_case(fun);
assert(fun == "hAvINg fUn");
return 0;
}
Others have already pointed out the mistake in your code so no need to repeat that. Instead this answer will give some alternative ways of implementing the task.
Your code is more C-style than C++ style. C++ has a number of functions/features that will allow you to write this in much shorter forms.
char ltrs[300] = "HaVinG FuN";
for (auto& ch : ltrs) ch = islower(ch) ? toupper(ch) : tolower(ch);
std::cout << ltrs << std::endl;
or
char ltrs[300] = "HaVinG FuN";
std::for_each(ltrs, ltrs + strlen(ltrs), [](char& ch)
{ ch = islower(ch) ? toupper(ch) : tolower(ch); });
std::cout << ltrs << std::endl;
or using the std::string
std::string str("HaVinG FuN");
for (auto& ch : str) ch = islower(ch) ? toupper(ch) : tolower(ch);
std::cout << str << std::endl;
Using these C++ functions/features makes the program shorter, easier to understand and the risk of bugs is lower.
Thanks for the help!!! I ended up figuring out my answer, while being able to maintain my less-than elegant code that is fitting with my class. Bipll ended up giving me what I was after, something to think about in terms that my original array was being modified each time.
I realize that my solution is sloppy and not appropriate for a work environment, but it is in-line with my homework assignment, as our teacher is encouraging us to learn C++ from the ground-up, not getting too much direct answers from places like SO. So I'm glad I learned a bit from here, as well as an indirect way to help me see my issues.
I ended up making a copy of my original array, and just passing that copy to my last reversing function. I was able to use the original array for the first 2 functions because the 1st function capitalized each character in the array, while the 2nd made them all lowercase. The 3rd function, the reverse, therefore had to have access to the original array, but in the 3rd order. The easiest way for a noob like me, given where I am in the class, was to make a copy of the 1st array and use that for the 3rd function.
//Snippet of code I needed
int main()
{
int index = 0;
cout << "Enter a string: " << endl;
const int Size = 300;
char ltrs[Size];
cin.getline(ltrs, Size);
char arrayCopy[Size];
char *ptr = nullptr;
char *ptr2 = nullptr;
ptr = ltrs;
//Copy of ltrs Array
//----------------------------------//
while (ptr[index] != '\0') //
{ //
arrayCopy[index] = ptr[index]; //
index++; //
} //
arrayCopy[index] = '\0'; //
//
ptr2 = arrayCopy; //
//----------------------------------//
return 0;
}
// Function to Reverse
void reverseFunct(char *ltrptr)
{
int count = 0;
while (ltrptr[count] != '\0')
{
if (isupper(ltrptr[count]))
{
ltrptr[count] = tolower(ltrptr[count]);
}
else
{
ltrptr[count] = toupper(ltrptr[count]);
}
count++;
}
cout << "---> reverse function: " << ltrptr << endl;
}

C++ Palindrome Creator Recursion Program

#include <iostream>
using namespace std;
void palindrome(char *s){
if (s[1] == 0)
{
return;
}
cout << s[0];
palindrome(++s);
cout << s[0];
}
int main(){
char s[30]="foobar";
palindrome(s);
cout << endl;
}
I have to create a recursive function that turns any cstring into a palindrome. This is a homework question and the only code I can modify is inside the palindrome function. This code almost works. The problem is it returns "foobaraboo" and leaves off the last letter. Any tips to point me in the right direction? I've played around with the code for quite a while and can't seem to figure out how to change it so the last character of the palindrome shows up.
You have two bugs in your logic. The first one:
if (s[1] == 0)
{
return;
}
This should be:
if (*s == 0)
{
return;
}
if your entire input is the string "x", your expected result is the palindrom "xx", but this bug will result in an empty string getting printed.
You also have a more fundamental bug:
cout << s[0];
palindrome(++s);
cout << s[0];
Your intent here is to print the current character, recursively print the rest of the palindrome string, and then re-print the same character.
But because of the ++s, you're printing the wrong character, the second time around.
This should be:
cout << s[0];
palindrome(s+1);
cout << s[0];
EDIT: a question has been raised whether you want the last character printed twice. If not, then this should be:
cout << s[0];
if (s[1])
{
palindrome(s+1);
cout << s[0];
}
Here you are
#include <iostream>
void palindrome( const char *s )
{
if ( s[0] )
{
std::cout << s[0];
if ( s[1] )
{
palindrome( s + 1 );
std::cout << s[0];
}
}
}
int main()
{
const char *s = "foobar";
palindrome( s );
std::cout << std::endl;
}
The program output is
foobaraboof

Modify contents of string literal C++ based on function constraints

I need to convert a given string literal to its lower case by passing the string as an argument to the function Lower(char *). The function can return only int.
In the main() i need the converted string to be accessible somehow.
Currently i am type casting the address of the tmp string in the Lower() function and then trying to dereference that address.
This is the code:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int Lower(char* str)
{
char tmp[100];
for(int i=0;i<=strlen(str);i++)
{
if(isupper(*(str+i)))
*(tmp+i) = *(str+i)+32;
else
*(tmp+i) = *(str+i);
}
return int(tmp);
}
int main()
{
char* str = "gOAt";
char *rc=(char *)Lower(str);
printf(rc);
return 0;
}
Again the function prototype cannot change ie the prototype must be int Lower(char *). However, "goat" must be somehow accessible in the main() function. How can this be done?
There are multiple things wrong with the posted code. My take would be that the int returned from the function is a status code, when it's 1, it signals that the conversion to lowercase was successful, 0 otherwise. Here is a working program that does the conversion:
#include <iostream>
using namespace std;
int lower(char* str)
{
int hasLower = 0;
while(*str)
{
if (*str >= 'A' && *str <= 'Z')
{
*str = (*str - 'A') + 'a';
hasLower = 1;
}
str++;
}
return hasLower;
}
int main(int argc, char** argv)
{
if (argc != 2) { cout << "No input! Exiting..." << endl; return 1; }
char* input = argv[1];
if (lower(input))
{
cout << "Lower case: " << input << endl;
}
else
{
cout << input << " isn't a valid string for lower-case conversion" << endl;
}
return 0;
}