Converting input from lowercase to uppercase using ASCII codes in C++ - c++

This is my first question here, so I've done my best to make this a good question.
I am creating a program that essentially takes user input and converts all characters to uppercase. I am using a for-loop to scan for lowercase characters using corresponding ASCII codes.
I am able to do this just fine using a character array that is assigned a string in-code: char text[] = "Text".
I want to be able to take user input and use it in the character array. I tried using getline(cin,myString) and assigning the character array with that, but it says array must be initialized with a brace enclosed initializer.
I kept the character array uninitialized because sizeof(text) isn't giving the correct size when the array is initialized. I was reading about using pointers but I'm still a bit fresh on that topic. Below is the code I wrote:
int main() {
// User input as a string
char textConvert[] = "This text will be converted to uppercase.";
cout << textConvert << endl;
int endChar = sizeof(textConvert); //Only gives correct size when array is uninitialized
for (int i = 0; i < endChar; i++) {
if (textConvert[i] >= 97 && textConvert[i] <= 122) {
textConvert[i] = textConvert[i] - 32;
}
}
cout << textConvert;
return 0;
}

Question:
I tried using getline(cin,myString) and assigning the character array with that, but it says array must be initialized with a brace enclosed initializer
Here the compiler works out the size of the array needed.
char textConvert[] = "This text will be converted to uppercase.";
If you want user input you need to allocate an array and specify size.
char textConvert[50];
Now you can read a line and copy it into the array:
std::string myString;
std::getline(std::cin , myString);
// Should check that the string is not more than 50 characters.
std::copy(std::begin(myString), std::end(myString), textConvert);
But really there is no need to do this at all. Just use the std::string and loop over the string. Best to avoid C constructs like arrays and use the C++ constructs that stop you making errors.
Size of String
This is not a good idea.
int endChar = sizeof(textConvert);
This measures the size of the array (not the size of the string). There is also an issue that arrays will very easily decay into pointers. When this happens sizeof() will give you the size of the pointer (probably 4 or 8) not the size of the array.
To get the size of a string use std::strlen() (include <cstring>).
But really you should be using std::string the C++ version of string that does its own memory management and re-sizes as required.
Magic Numbers
Prefer not to use magic numbers:
if (textConvert[i] >= 97 && textConvert[i] <= 122) {
textConvert[i] = textConvert[i] - 32;
}
These magic numbers make the code hard to read. You can use character constants instead.
if (textConvert[i] >= 'a' && textConvert[i] <= 'z') {
textConvert[i] = textConvert[i] - ('a' - 'A');
}
Prefer the standard Library
But doing this manually is not recommended. You should use the standard library routines.
std::islower() . // Check if a character is lower case.
std::toupper() . // Convert a lowercase character to upper.
// include <cctype>
C++ Example
Try this:
#include <iostream>
#include <string>
#include <cctype>
int main()
{
std::string myString;
while(std::getline(std::cin, myString)) {
std::cout << "User Input: " << myString << "\n";
for(auto& c: myString) {
c = std::toupper(c);
}
std::cout << "Upper Case: " << myString << "\n";
}
}

Since you are dealing with ASCII, you can just use std::toupper.
No need to write custom code to do it, the standard library has you covered.

Related

Char outputting random characters at the end of the sentence

#include <iostream>
#include <string.h>
using namespace std;
void crypt(char* sMsg)
{
cout << "Original Message: '" << sMsg << "'" << endl;
int length = strlen(sMsg);
char sMsg_Crypt[3][length];
/* sMsg_Cryp[3]
[0] CRYPT LETTERS, ASCII + 3
[1] INVERT CHAR
[2] HALF+ OF SENTENCE, ASCII - 1
*/
for (int i=0; i<length; i++)
{
if (isalpha((int)sMsg[i]))
sMsg_Crypt[0][i] = sMsg[i] + 3; // DO ASCII + 3
else
sMsg_Crypt[0][i] = sMsg[i];
}
cout << "Crypt[0]: '" << sMsg_Crypt[0] << "'" << endl;
}
int main()
{
char sMsg[256];
cin.getline(sMsg,256);
crypt(sMsg);
return 0;
}
Input:
Hello World! Testing the Cryptography...
Output:
Original Message: 'Hello World! Testing the Cryptography...'
Crypt[0]: 'Khoor Zruog! Whvwlqj wkh Fu|swrjudsk|...Çi­o'
Why this Çi­o is comming out??
For starters variable length arrays like this
int length = strlen(sMsg);
char sMsg_Crypt[3][length];
is not a standard C++ feature.
You could use at least an array of objects of the type std::string like for example
std::string sMsg_Crypt[3];
Nevertheless the problem is that the array sMsg_Crypt[0] dies not contain a string. That is you forgot to append inserted characters in the array with the terminating zero character '\0'.
You could write after the for loop
sMsg_Crypt[0][length] = '\0';
provided that the array (if the compiler supports VLA) is declared like
char sMsg_Crypt[3][length+1];
Firstly, you can't define a static char array like this: char sMsg_Crypt[3][length];. That is because the length is not a const type, meaning the size of the array will be sMsg_Crypt[3][0] (this is because the size is not known at compile time). In MSVC, it'll flag an error (by IntelliSense). Since you know the size beforehand (256), you can replace the length with 256.
The second fact is that you're using C++ and you have access to std::string. So without using a char buffer, use std::string instead. It would look something like this: std::string sMsg_Crypt[3];
The last fact is that, for a string to be read correctly, it needs to be null-terminated ('\0' at the end). This means that the ending character must be '\0'. In the case of std::string, it does it for you.

Extra zero char at end of string appears in C++ for range loop

The following code
#include <iostream>
#include <string>
int main()
{
std::string s = "abc";
for (char c : s)
std::cout << (int) c << " ";
}
prints "97 98 99 ".
The following code
#include <iostream>
int main()
{
for (char c : "abc")
std::cout << (int) c << " ";
}
prints "97 98 99 0 ".
Where is the extra 0 coming from in the second code?
The literal "abc" is a const char[4] type: the final element is the NUL terminator (with value 0).
In the second snippet, the value of the NUL terminator is printed as the code is describing an iteration over that entire const char[4] array.
In the first snippet, the underlying iterator technology of the std::string class sets the end iterator (which is not reached in the short form for loop) to the NUL terminator. This behaviour is consistent with s.size().
In the first snippet you are iterating over a string using a range based loop. The std::string type has .begin() and .end() iterators. The range based loop uses those to mark the beginning and the end of the range.
In the second snippet, you are using a range based loop to iterate over a string literal. A string literal is basically an array of characters that has an extra hidden \0 character at the end. This character is convertible to integer value of 0. Hence the extra 0 in the output.
C++ has two types of strings with different properties:
C Strings and String Literals
They are fixed-size null-terminated character arrays (max. size determined at compile time). "abc" is called a string literal which you can think of as a character array containing { 'a', 'b', 'c', '\0' }. Your range-based for loop is iterating over all characters in the array including the null terminator. The C way of printing the data without the null termination would be:
char ca[] = "abc";
char *c = ca;
while (*c)
std::cout << (int) *(c++) << " ";
Note that this old-fashioned way of fiddling with raw pointers is not recommended - it's just too easy to shoot yourself in the foot.
C++ Strings and C++ String Literals
std::string provides a string implementation that can handle arbitrary length strings (memory allocated dynamically at run time). C++ strings are objects that have their own way of handling length which doesn't require null termination. The std::string class provides iterators that enable us to write loops like
std::string s = "abc";
// Traditional loop with iterators:
for (auto i = s.begin(); i != s.end(); i++)
std::cout << (int) *i << " ";
// Range-based for loop:
for (char c : s)
std::cout << (int) c << " ";
The C string "abc" is passed to std::string's constructor which stores it in its internal format.
Note that C++14 also supports C++ string literals: "abc"s (note the operator s at the end). In your example you can use them like so:
using namespace std::string_literals;
for (char c : "abc"s)
std::cout << (int) c << " ";
}

How to explain weird characters at the end of my char array, and the wrong result of using strlen function in my code

I am a complete beginner so the code may seem to be easy, but I cannot find a solution why it returns such values as:
input: kkkk
output:
14
kkkkřřřř╩┬ëŢ
Suprisingly the code works fine with online compilators, but not with the Visual Studio.
#include<iostream>
#include<string.h>
int main()
{
char word[20];
std::cin >> word;
int length = strlen(word);
int p = length - 1, i = 0;
char *var=new char [length];
while (i < length&&p>=0)
{
var[i]= word[p];
p--;
i++;
}
std::cout <<strlen(var)<<endl<< var;
if (!strcmp(var, word)) std::cout << "\nThe word is a palindrome";
return 0;
}
I can not use strings because my University doesn't allow to do so. I also know there are many different ways to attend to this problem but I just really want know what I have done wrong in this one :/
Your "copy routine" copies each character, but it does not copy the string termination character. Note that C-style strings as used in functions like strlen or strcmp need to be 0-terminated, and even cout <<, when getting a parameter of type char*, treats this as a C-style string: It will read until finding the terminating '\0', and if you do not write one, it will read beyond the boundaries you think it should do.
If your write
...
}
var[length] = '\0';
std::cout <<strlen(var)<<endl;
...
it should work.

How do I combine two strings?

The question requires combining two strings(the longer string in the front and the shorter one after the longer one) without using <string> header file.Each string inputted can't exceed 20 characters.
My logic behind this is:
first use strlen to get the length of the str1 and str2,
use str3 to store the longer string, and str4 to store the shorter.
add str3 and str4 to str5
Here is my code:
#include<iostream>
using namespace std;
int main()
{
// combine two strings , longer in the front, and shorter
// after it. do not use strcat
char str1[20],str2[20],str3[20],str4[20],str5[40];
// str1 and str2 stores original data, str3 stores longer
// and str4 stores shorter, str5 stores total
int j=0;
cin.getline(str1,20);
cin.getline(str2,20);
if(strlen(str1)<=strlen(str2))
// give longer string value to str3,shorter to str2
{
for (int i=0;i<20;i++)
{
str3[i]=str2[i];
str4[i]=str1[i];
}
}
else
{
for (int i=0;i<20;i++)
{
str3[i]=str1[i];
str4[i]=str2[i];
}
}
for(j=0;str3[j]!='\0';j++)
{
str5[j]=str3[j];
}
for(int i=j;i<40;i++)
for(int m=0;m<20;m++)
{
str5[i]=str4[m];
}
cout<<str5<<endl;
return 0;
}
Here is the ouput:
What's my problem here? What are those characters in between the two strings? Thank you!!
Especially since you explicitly mentioned being a beginner, the solution is to use std::string:
#include <iostream>
#include <string>
int main() {
std::string a;
getline(std::cin, a);
std::string b;
getline(std::cin, b);
// Ensure that the longer string goes to the front.
if (a.size() < b.size());
swap(a, b);
std::string result = a + b;
std::cout << result << '\n';
// Or, simply:
std::cout << a << b << '\n';
}
The message here is that C++, despite its quirks, is a very high level language if you rely on its library instead of implementing every low level operation from scratch.
Everything is fine (!) up to this point
for(int i=j;i<40;i++)
for(int m=0;m<20;m++) // This loop runs m=0 to 20 for each position of i
{
str5[i]=str4[m];
}
For each index i you are copying in all 20 elements from str4, leaving just the value at str4[19] which could be anything
Just increment i and m by one together
int m = 0;
for(int i=j;i<40;i++)
{
str5[i]=str4[m++];
}
You are copying the entire 20 characters, 40 characters in the loop into the variables. stop copying when you find a '\0' character.
But using the std::string will make life simpler :)
Using std::string is nice and all but here's a few tips for working with char*:
1) You shouldn't copy strings to separate shorter and longer string, just use pointers and then work with these pointers, something along these lines:
const char *longer_string = 0, *shorter_string = 0;
if(strlen(str1)<=strlen(str2))
{
shorter_string = str1;
longer_string = str2;
}
else
{
shorter_string = str2;
storter_string = str1;
}
2) Using strcpy and strcat to combine strings could make life a lot easier:
char *combined_string = new char [strlen (shorter_string) + strlen (longer_string) + 1];
strcpy (combined_string, longer_string);
strcat (combined_string, shorter_string);
Some compilers would say that these functions aren't safe and you have to stick to _s versions, but I guess it's entirely up to you.
Since this is obviously homework: I'll just point out the existence of the function strcat, and the fact that you can use char* to the arrays, and just swap them, without having to recopy anything between the initial read and the concatenation (which means that you only need two arrays: one for each of the inputs, and one for the final value).
And also, when calculating sizes, etc. do not forget that C style strings have an extra '\0' at the end, and make allowances for it.
As #David Sykes has pointed out, the problem is with your for loop. So when you read input from cin ,it is not necessary that your input string contains 20 character. But in you form loop you are looping through those string beyond their length which may contains garbage characters. Example
char str1[20]
cin.getline(str1,20);
cout << str1[19] << endl;
Suppose your input for above code is "ABCD" which contains only 4 characters but your array has capacity of 20. So the remaining space has junk characters and when you will try to print any thing beyond actual length you will get wild character as you are getting in your code.

c++ int store as character in char* conversion without any API

how can we store int value in char* as representing character in c++.. for example, i want to store 10..char* p is a character pointer and i want to store 10 as character in that pointer...because i want to write iteration that generates character stream based on integer value.how to do char concatenation with integer(as char) with The similar java code be as:
for(int i=0; i<10; i++)
{
string temp=value+i;//here i want to use char* to represent string in c++
System.out.println(temp);
}
I know you said C++, but you also said char* so i am going to treat it as C. With C, you can't really do concatenation like that. The best way to do it would be to calculate the number of characters required, malloc that, then just store the characters in the char array. And remember to free it when you're done using it! In C, you have to do everything yourself!
I'm a little confused about what you're trying to do, but here's some information that I think will probably help you work it out:
In C++, you should primarily use std::string to hold strings of characters.
In regular C, the convention is to use a char* to hold a list of characters - these char*'s have to be null terminated ending in \0 so that your code knows where to stop printing the string of characters.
Preferring the C++ way, you can concatenate strings with the + operator:
Here's an example:
std::string myString = "H";
myString += "e";
myString += "l";
std::cerr << myString; //prints "Hel" to console.
You can also use a string stream which can mix data types:
std::stringstream ss;
ss << "h" << "e" << 7 << myCustomType << std::endl;
One other thing that's good to know is you can store an integer value in a char and it will work out the ascii representation when you print it.
For example:
char x = 65; //x = capital A.