Array does not store beyond first space - c++

the input provided through temp is a sentence, and I need to remove spaces and special characters but 'mes' stores only the first word
#include <iostream>
#include <cmath>
using namespace std;
int main(){
char mes[51];
char pas[11];
char tem[51];
cin.getline(tem,51);
cin.getline(pas,11);
for(int i=0;i<51;i++){
mes[i]='\0';
}
for(int t=0;t<sizeof(pas);t++){
pas[t]=tolower(pas[t]);
}
for (int i=0;i<50;i++){
char c=tem[i];
int ch=(int)c;
if(( ch >= 65 && ch <= 90) || ( ch >= 97 && ch <= 122)){
if( ch >= 65 && ch <= 90)
ch+=32;
mes[i]=(char)ch;
}
else
continue;
}
cout<<mes<<endl;

Notice that you are setting each index in mes to '\0', aka NUL. When you are iterating through tem checking if each character is a letter, you are inadvertently separating the words by \0 inside mes. You need to have a separate index that allows you to add the letters when you find them.
Your for loop could look like this.
int currentIndex = 0;
for (int i = 0; i < 50; i++){
char c = tem[i];
int ch = (int)c;
if(( ch >= 65 && ch <= 90) || ( ch >= 97 && ch <= 122)){
if( ch >= 65 && ch <= 90)
ch+=32;
mes[currentIndex++]=(char)ch;
}
else
continue;
}
This way, you will be adding the letter directly after the next, rather than something like Hello\0World.
Also, remember that cout will only print strings up until it finds a \0 character. Technically you are storing all letters you find in a sentence, but they are separated by \0 and therefore, cout only prints the first word.

Related

C++ - Changing single lowercase charachter in a word to uppercase and vice versa using struct data type

As you can see from the title I want to change lowercase charachter in word to uppercase and vice versa.
Also I need to use struct object (in my case name).
I have a problem when I change charachter from lowercase to uppercase it only changes in the first word not in the second,third and so on. I am also reading words from file
Here is the input file
Aayak Audi
Ahmed Golf7
Samed Golf5
Here is the code
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <cctype>
using namespace std;
struct pismaStr
{
string ime;
string objekat;
};
void malaVelikaSlova (string name)
{
for (int i = 0; i < name.length()-1; i++)
{
if (name.at(i) >= 'A' && name.at(i) <= 'Z')
name.at(i) += 32;
else if (name.at(i) >= 'a' && name.at(i) <= 'z')
name.at(i) -= 32;
cout << name;
break;
}
}
int main()
{
ifstream pismo;
pismo.open("pismo.txt");
ofstream novoPismo;
novoPismo.open("novaSlova.txt");
pismaStr stvari[200];
int brojStvari = 0;
while(pismo >> stvari[brojStvari].ime >> stvari[brojStvari].objekat)
{
brojStvari++;
}
for (int i = 0; i < brojStvari; i++)
{
vector <pismaStr> vec = {pismaStr{stvari[i].ime}};
for (auto obj : vec)
{
malaVelikaSlova (obj.ime);
}
}
Here is the output:
aayak
ahmed
samed
It was:
Aayak
ahmed
samed
I want it to look like this
aAYAK
sAMED
aHMED
How can I fix this?
Any tips?
Tangential,
but it will be an issue, is this line
for (int i = 0; i < name.length()-1; i++)
This will loop from name[0] to name[name.length() - 2]. The std::string::length returns the number of usable characters. It does not include the null terminator, so you don't need to subtract 1. It should be
for (int i = 0; i < name.length(); i++)
Your bigger problem
is the break statement at the end of your loop (indentation added for clarity)
for (int i = 0; i < name.length()-1; i++)
{
if (name.at(i) >= 'A' && name.at(i) <= 'Z')
name.at(i) += 32;
else if (name.at(i) >= 'a' && name.at(i) <= 'z')
name.at(i) -= 32;
cout << name;
break; // <--- this exits the loop entirely
}
Your break; tells the program to exit the loop immediately. No further iterations of the loop are performed. Your cout statement is also within the loop. Once you do get the loop running for each iteration, you'll output each step of the transformation. To only output it once (at the end) you put it outside of the loop. If you want to loop over every character (and you do), your final code looks like
void malaVelikaSlova (string name)
{
for (int i = 0; i < name.length() - 1; i++)
{
if (name.at(i) >= 'A' && name.at(i) <= 'Z')
name.at(i) += 32;
else if (name.at(i) >= 'a' && name.at(i) <= 'z')
name.at(i) -= 32;
}
cout << name;
}
Other things you can change
You don't need to do bounds checking on your string indexes, since you're looping based on the string length, and it's not changing, so you don't need to extra overhead of std::string::at. You can just use the index operator:
// name.at(i); // <-- no need to do this anywhere
name[i] // <-- slightly faster
Since you're applying some operation to each element (character) in your container (string), this is a great candidate for std::transform, from the <algorithm> library. I'm also using a lambda expression here, which is a great too from C++ to get familiar with.
https://en.cppreference.com/w/cpp/algorithm/transform
https://en.cppreference.com/w/cpp/language/lambda
void malaVelikaSlova (string name)
{
std::transform(
name.begin(),
name.end(),
[](char c) -> char
{
if (c >= 'A' && c <= 'Z')
return c + 32;
if (c >= 'a' && c <= 'z')
return c - 32;
return c; // <-- for all other characters
}
);
std::cout << name << "\n";
}
You could even take advantage of the std::isupper, std::islower, std::toupper, and std::tolower functions to make your code more explicit. Note that std::string is an alias for std::basic_string<char> (its value type is char), the upper and lower functions operate on unsigned chars, so you'll need to convert the chars to unsigned chars:
https://en.cppreference.com/w/cpp/string/basic_string
https://en.cppreference.com/w/cpp/string/byte/tolower
https://en.cppreference.com/w/cpp/string/byte/toupper
https://en.cppreference.com/w/cpp/string/byte/isupper
https://en.cppreference.com/w/cpp/string/byte/islower
void malaVelikaSlova (string name)
{
std::transform(
name.begin(),
name.end(),
[](unsigned char c) -> unsigned char // <-- must convert to unsigned to be safe with upper/lower functions
{
if std::isupper(c) return std::tolower(c);
if std::islower(c) return std::toupper(c);
return c; // <-- for all other characters
}
);
std::cout << name << "\n";
}

What is the proper way of reading a composite key and a numeric value from an input file?

I'm trying to read a text file consisting of numerous strings which either represent a key/value (the key is a car number in a format of a letter/' '/3digits/' '/2letters; the value is unsigned long long; \t or ' ' between them) or an empty line, e.g.:
empty line
empty line
Z 999 ZZ 80
A 000 AA 124
Z 666 ZZ 42
I am using a cin.getline() function for that, reading a whole line and going through every character, saving a key and a value into an 'element' variable and pushing it into a vector afterwards. But for some reason the program seems to work unexpectedly, giving a weird output:
0
0
Z 999 ZZP 80
A 000 AA| 124
Z 666 ZZ* 42
So far I have been trying to analyse what could go wrong but I just can't see it. I've also tried using other tools like scanf() or cin.get() but failed miserably. Can someone please explain to me why this is happening and maybe show a more correct way of solving this task? Here is the code:
struct kv {
char key[8];
unsigned long long val;
};
int main()
{
std::vector<kv> data_vector;
kv element;
char str[64] = {};
char num[32] = {};
while (std::cin.getline(str, 64)) {
if (str[0] == ' ' || str[0] == '\n' || str[0] == '\t' || str[0] == EOF) {
continue;
}
size_t i = 0, n = 0;
for (i = 0; i < 8; i++)
element.key[i] = str[i];
while (!(str[i] >= '0' && str[i] <= '9'))
i++;
while (str[i] >= '0' && str[i] <= '9')
num[n++] = str[i++];
element.val = atoi(num);
data_vector.push_back(element);
for (n = 0; n < 32; n++)
num[n] = 0;
for (i = 0; i < 64; i++)
str[i] = 0;
}
for (size_t i = 0; i < data_vector.size(); i++) {
std::cout << data_vector[i].key << "\t" << data_vector[i].val << std::endl;
}
return 0;
}
EDIT: as #JimRhodes pointed out, changing char key[8] to char key[9] and adding element.key[8] = '\0' helped, but empty lines are still being processed the wrong way (as they should be ignored), giving an output of 0.
I think you may not be understanding how std::cin.getline() works. First of all, you do not want to test the return value of std::cin.getline() for true or false. You need to check for eof or fail. Secondly, std::cin.getline() discards the newline character so there is no need to check for '\n'. Your loop could start like this:
for ( ; ; )
{
str[0] = '\0'; // Clear any previous data
std::cin.getline(str, 64);
if ( std::cin.eof() )
{
break; // No more data, exit loop
}
if ( std::cin.fail() || (str[0] < 'A') )
{
continue; // Empty line or line does not start with a letter
}
. . .

caesar cipher algorithm c++

i'm trying to implement Ceaser cipher in c++ language
#include <iostream>
#include <string>
#include <locale>
using namespace std;
int main()
{
string word;
getline(cin,word);
for(int i=0; i<word.length();i++)
{
if(isalnum(word[i]))
{
//shift by 3
word[i]+= 3;
}
}
cout << word ;
return 0;
}
what i want is to limit the output also for only letter and number .
for example if i want to shift z by 3 the output would be 'c' and not '}' as in my code .
Compilers are much better at handling the tedious details than humans, so in this case, I would write the code to show clearly what you intend, and then let the compiler figure out the numbers.
For example, if you want to shift a letter, don't you really just want to add 3 to the index of the letter in the range A to Z, and then mod by 26 -- the number of letters from A to Z? This is really what you want -- rotate around the circle of LETTERS from A to Z, of which there are 26, and not worry about ASCII values.
In that case, you can let the compiler figure it out for you:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int shift = 3;
char* input = "Is it 90 with a ZERO?";
printf("%s\n", input);
int length = strlen(input);
char* output = malloc(length + 1);
output[length] = '\0';
for (int i = 0; i < length; i++)
{
char c = input[i];
if (c >= 'A' && c <= 'Z')
{
c = (((c - 'A') + shift) % 26) + 'A';
}
else if (c >= 'a' && c <= 'z')
{
c = (((c - 'a') + shift) % 26) + 'a';
}
else if (c >= '0' && c <= '9')
{
c = (((c - '0') + shift) % 10) + '0';
}
output[i] = c;
}
printf("%s\n", output);
}
Why would you want to take on that responsibility, if you are not worried about speed or memory footprint?
You have to make sure it does not go out of the valid range for ASCII letters. A way of doing this is to convert the input to lowercase, then make sure that when the shift is added, it does not exceed 122 (z's value in ASCII).
if (word[i] + SHIFT > 'z') {
SHIFT -= 123 - word[i];
word[i] = 'a'; // go back to the beginning
word[i] += SHIFT; // add on the remaining amount
}
This should work.This assumes that there will be only lower case letters.
word[i]+= 3;
//at this point word[i] might have cross the ascii limit for lower case letters
ie may be word[i]>122.Ascii range for lower case letters is 97-122
So we use mod to wrap it around.
But now may be word[i]<97 which is again out of range so we add 97 to it.
word[i]%=123;
if(word[i]<97)word[i]+=97;
Example z
word[i]+=3 makes word[i] as 125 //out of range
word[i]%=123 //word[i]=3
word[i]+=97 //word[i]=99=c

Scan for ASCII values of string characters

I want to check if a string contains any characters other than 0-9 or A-Z and if it does, stop the program. This is what I did:
string number_in;
for (int i = 0; number_in[i] == '\0'; i++)
{
if ( (number_in[i] < 48) || ( (number_in[i] > 57) && (number_in[i] < 65) ) || (number_in[i] > 90) )
{
cout << "\nInput number contains incorrect characters!\n";
getchar;
return 0;
}
}
But whichever string I would enter, it always skips the for loop. Why is that so?
number_in[i] == '\0' seems to be incorrect. It is the condition for the loop to continue to run.
However, there is an easier solution using std::isalnum and std::all_of:
bool stopProgramm = !std::all_of( std::begin(str), std::end(str),
[] (unsigned char c)
{ return std::isdigit(c) || std::isupper(c); } );
number_in[i] == '\0' should be number_in[i] != '\0'. The for loop to runs while the condition is true.
You should do:
#include <cctype>
// ...
char const c = number_in[i];
if ( !(isascii(c) && (isdigit(c) || isupper(c))) ) {
// ...
}
Strictly speaking, isascii(c) isn't needed, but, if you want to be cross-platform, the other is*() functions break on Windows if c isn't ASCII.

Arithmetic on C++ strings

This code really confuses me, it is using some Stanford libraries for the Vector (array) class. Can anyone tell me what is the purpose of int index = line [j] - 'a'; why - 'a'?
void countLetters(string filename)
{
Vector<int> result;
ifstream in2;
in2.open(filename.c_str());
if (in.fail()) Error("Couldn't read '" + filename + "'");
for (int i = 0; i < ALPHABETH_SIZE; i++)
{
result.add(0); // Must initialize contents of array
}
string line;
while (true)
{
getLine(in, line);
// Check that we got a line
if (in.fail()) break;
line = ConvertToLowerCase(line);
for (int j = 0; j < line.length(); j++)
{
int index = line [j] - 'a';
if (index >= 0 && index < ALPHABETH_SIZE)
{
int prevTotal = result[index];
result[index] = prevTotal +1;
}
}
}
}
The purpose of the code:
Takes a filename and prints the number of times each letter of the alphabet appears in that file. Because there are 26 numbers to be printed, CountLetters needs to create a Vector. For example, if the file is:
Characters in a string are encoded using a character set... typically ASCII on hardware common in English language systems. You can see the ASCII table at http://en.wikipedia.org/wiki/ASCII
In ASCII (and most other character sets), the numbers representing letters are contiguous. So, this is the natural way to test whether the character at index j in character-array line is a letter:
line[j] >= 'a' && line[j] <= 'z'
Your program is equivalent to that, in an algebra-kind of sense it subtracts a from both sides (knowing that a is the first character in the character set):
line[j] >= 'a' - `a` && line[j] <= 'z' - `a`
line[j] >= 0 && line[j] <= 'z' - `a`
Replacing "<= z - a" with am equivalent:
line[j] >= 0 && line[j] < ALPHABET_SIZE
where ALPHABET_SIZE is 26. This trades a dependency on knowing z is the last character of your character set for knowing how many characters are in your character set - both are a little fragile, but fine if you know you're dealing with a well-known, stable character set encoding.
A better way to check for a letter is to use the isalpha() predicate: http://www.cplusplus.com/reference/clibrary/cctype/isalpha/
"a" is at the beginning of ASII chars.
int index = line [j] - 'a';
if (index >= 0 && index < ALPHABETH_SIZE)
These two line of code is to just if line[j] is a character.