strspn Strange behavior under c++, why? - c++

Here is a program I made:
#include <iostream>
#include <cstring>
using namespace std;
int main() {
char frase1 [100];
char frase2 [100];
cin >> frase1;
cin >> frase2;
char * parola1 = strtok (frase1, " .");
char * parola2 = strtok (frase2, " .");
int i;
i = strspn (parola1, parola2);
int j;
j = strspn (parola2, parola1);
cout << i << " " << j;
return 0;
}
It should ask for 2 sentences that will be stored into frase1 and frase2, then two tokenizers set two pointers to the first word of their respective array, then I should get back the values i and j, wich are ints given by the strspn function.
So when the terminal shows up should be able to put, for example, "veritas omnia vincit" and "vetirsa omnia vincit" and then get 7 7 as output.
Instead, I insert the first sentence and it returns the values of the strspn between the first and the second word of the first sentence (veritas, omnia).
This is an attempt at isolating a problem showing up in a bigger program wich I'll show you right away:
#include <iostream>
#include <cstring>
using namespace std;
void eliminaVocali (char [], char []);
int controlloAnagramma (char*, char []);
bool controlloParola (char[]);
int main() {
char frase [10];
cin >> frase;
cout << "yolo1";
char fraseCorretta [100];
cout << "yolo";
eliminaVocali(frase, fraseCorretta);
if (controlloParola(fraseCorretta)) cout << "TRUE!!";
else cout << "FALSE :(";
}
void eliminaVocali (char frase [], char fraseCorretta []){
int counter = 0;
for (int i = 0; i < 100; i++){
if (frase[i] != 'a' && frase[i] != 'e' && frase[i] != 'i' && frase[i] != 'o' && frase[i] != 'u'){
fraseCorretta[counter] = frase[i];
counter++;
}
}
}
bool controlloParola (char frase []){
char * parola = strtok (frase, " .");
if (controlloAnagramma (parola, frase) > 2) return true;
while (parola != NULL){
parola = strtok(NULL, " .");
if (controlloAnagramma (parola, frase) > 2) return true;
}
return false;
}
int controlloAnagramma (char * parola, char frase []){
int counter = 0;
char * check = new char [100];
check = frase;
char * parola2 = strtok (check, " .");
if (strlen(parola) == strlen(parola2) && strlen(parola) == strspn(parola, parola2) && strlen(parola) == strspn(parola2, parola)) counter++;
while (parola2 != NULL){
parola2 = strtok (NULL, " .");
if (strlen(parola) == strlen(parola2) && strlen(parola) == strspn(parola, parola2) && strlen(parola) == strspn(parola2, parola)) counter++;}
delete[] check;
return counter;
}
This program receive a sentence, delete all the vowels from it and then check if among the words newly formed there are 2 wich one is anagram of another.
eliminaVocali delete the vowels
controlloParola takes one word of the sentence at a given time and send it to controlloAnagramma
controlloAnagramma take the word and search into the whole sentence for an anagram
This program gives
1 [main] testingstuff 93304 cygwin_exception::open_stackdumpfile:
Dumping stack trace to testingstuff.exe.stackdump
Where testingstuff is the program name.
The problem should be into controlloAnagramma, where I use strlen and strspn.
Know fact that can be useful: Neither of the 2 yolo cout into the main is ever printed.
Please note this is a didactic program, I can only use c++ with <cstring>.
The question is, why does the strspn command behave this way? It should solve the big program. Thanks in advance.
EDIT:
cin >> frase1;
cin >> frase2;
Shoud be:
cin.getline(frase1, 100);
cin.getline(frase2, 100);
As #anton-savin pointed out.
Also
check = frase;
Should be
strcpy (check, frase);
Error persist anyway.

cin >> frase1;
cin >> frase2;
operator>> reads strings word by word, so frase1 becomes "veritas" and frase2 becomes "omnia". To read the input line by line use getline:
cin.getline(frase1, 100);
cin.getline(frase2, 100);

Related

Why is c++ treating the space bar as null ('\0')?

my professor asked us to determine the number of vowels in userString without a call to the library.
I am using '\0' in a for loop to figure out when will the string the user input will come to an end because I don't know the exact size they are going to input for the string. I am a beginner programmer so please don't give me complcated answer! thanks.
I have for(int i = 0; userString[i] != '\0'; i++)
but the program is treating the space bar as a null character too so
I get a problem in the output,
if I have a space in the commend line is treats it as a null and terminates the proram
loop at the pictue of the 2 different outputs for refrence.
As you can see in output 1
When i have "MianJalal" I get 9 in the terminal but for
output 2 When I have "Mian Jalal" (with a space), it treats the space as null and gives me 4, I am aware that '\0' is space in the special chartacer in c++ but it's also null, how can I tell the program i mean null not space?
this is my code,
#include <iostream>
using namespace std;
int main()
{
int numOfVowels = 0;
int length = 0;
char userString[50]; // The string the user will input
cout << "Enter a sentence to find out how many vowels are in the sentence" << endl;
cin >> userString;
for(int i = 0; userString[i] != '\0'; i++) // '\0' means null in a string in c++; if a user doesn't use a index in a char string
{ // the program will know it's a null in syntax '\0'
if(userString[i] == 'A' or userString [i] == 'a' or userString[i] == 'i')
{
numOfVowels++;
}
length++;
}
cout << length << endl;
return 0;
}
The problem is that the operator >> uses the space as a delimiter. So when reading userString it stops at the first space. To avoid this a method could be to use istream::getline (char* s, streamsize n ) function, that reads the entire line up to the '\n' character, or the supplied size limit.
#include <iostream>
using namespace std;
int main()
{
int numOfVowels = 0;
int length = 0;
char userString[50]; // The string the user will input
cout << "Enter a sentence to find out how many vowels are in the sentence" << endl;
cin.getline(userString, sizeof(userString));
for(int i = 0; userString[i] != '\0'; i++) // '\0' means null in a string in c++; if a user doesn't use a index in a char string
{ // the program will know it's a null in syntax '\0'
if(userString[i] == 'A' or userString [i] == 'a' or userString[i] == 'i')
{
numOfVowels++;
}
length++;
}
cout << length << endl;
return 0;
}

How do I use cin to get a string instead of hard-coding it?

As a homework exercise we were asked to use strchr to count the amount of times a single letter appears in a string of text. It needs to count upper or lower cases as equal. It was suggested we use some sort of bit operations.
I managed to get a working program.
But i would like to make the program more interactive by allowing me to use a cin to input the string instead of typing the string directly into the source code (Which was asked by the exercise).
Is it possible to do this? Or is it not possible in the way i wrote this code.
#include <iostream>
#include <cstring>
using namespace std;
int main(){
const char *C = "This is a necesarry test, needed for testing.";
char target = 'A';
const char *result = C;
const char *result2;
int count = 0;
int j[26] ={0};
//================================================================================================================================================
for(int i = 0; i <= 51; i++){
if (i == 26){
target = target + 6;
}
result2 = strchr(result, target);
while(result2 != NULL){
if (result2 != NULL){
result2 = strchr(result2+1, target);
if (i <= 25){
j[i] = j[i] +1;
}
if(i > 25){
j[i-26] = j[i-26] +1;
}
cout << target << "\t";
}
}
cout << target << endl;
target++;
}
char top = 'a';
for(int o = 0; o<= 25; o++){
cout << "________________________________\n";
cout << "|\t" << top << "\t|\t" << j[o] << "\t|" << endl;
top++;
}
cout << "________________________________\n";
}
Simply use getline() to get a string of characters from the console. Using getline you can also consider the spaces in the user input.
string input;
getline(cin, input);
Now to use this with the strchr functionn you simply have to convert this into a C Type string which can be done as follows :
input.c_str
This returns a C type string so you can put this as an arguement to the function,
You will need
#include <string>

Reversing char array

When I print out text2 I see that it is definitely not the reverse of the string I gave it and I'm not sure why that is. When I put in "test" I get stuff like "ȍ\2200+". Can I use strncpy on char arrays? Maybe it needs to be done with a loop - not sure. Any help would be appreciated. :)
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char text[79], text2[79];
bool input = true;
while (input) {
cout << "Please give me a line of text to examine: ";
cin.getline(text, 79);
for(int i = 0; i < strlen(text); i++ )
cout << text[i];
// test to see if it is a palindrome
strncpy(text, text2, 80);
reverse(text2, text2 + strlen(text2));
printf("%s", text2); `// when I print this out I get something odd`
if (strcmp(text, text2) == 0)
cout << " is a palindrome!" << endl;
else
cout << " is not a palindrome." << endl;
if (strcmp(text, "END") == 0)
input = false;
else
cout << "\ntype END to exit the program" << endl;
} // end while loop
} // end main
It seems you're using strncpy in a wrong way: you probably want to copy text into text2, not the other way around.
There's a much simpler way to test whether a string is a palindrome, namely:
bool is_palindrome(const char* s, size_t n) {
size_t i, j;
i = 0, j = n-1;
while (i < j && s[i++] == s[j--])
;
return i >= j;
}
Why not use std::vector<char> and std::reverse from <algorithm> to handle your problem?
I would do something like below: (note that I'm using C++11 range-based for loop and auto which you can change to a regular for loop and use std::string line if you don't have a compiler supporting this).
int main()
{
cout << "Please give me a line of text to examine: ";
auto line = ""s;
getline(cin, line);
// Push back every character to the vector
vector<char> vtext;
for (const auto &elem : line)
vtext.push_back(elem);
// Create a copy of the vector<char> and reverse the copy
vector<char> vtext_reversed{vtext};
reverse(begin(vtext_reversed), end(vtext_reversed));
// Print the line reversed
cout << "\nThis is the line reversed: ";
for (const auto &elem : vtext_reversed)
cout << elem;
}
Typically you'll see this reversal technique for char*:
void reverse(char* s) {
if(!s) return;
size_t n = strlen(s);
for(size_t i = 0; i < n/2; ++i) {
char tmp = s[i];
s[i] = s[n - i - 1];
s[n - i - 1] = tmp;
}
}
This will not work, however, with non-ASCII characters. The reason is that non-ASCII characters require multiple bytes to represent.
You will need to use wide characters to handle multi-byte codepoints, but the logic should follow above.

Consonant counting program not returning number of consonants

This program is supposed to compare the list of consonants to a user input list of letters and print out the number of consonants in the user's input. However, it just prints 0. I'm very new to C++ and am not experienced in finding logic errors.
#include <iostream>
#include <cctype>
#include <string>
using namespace std;
int counter(char *, char);
int main()
{
const int size = 51;
char input[size];
const char consonants[22] = "bcdfghjklmnpqrstvwxyz";
cout << "Enter your letters." << endl;
cin >> input;
cout << consonants << "appears";
cout << counter(input, consonants[22]) << "times" << endl;
}
int counter(char *strPtr, char ch)
{
int times = 0;
while (*strPtr != '\0')
{
if (*strPtr == ch)
times++;
strPtr++;
}
return times;
}
I'm aware you're new to C++, and this looks like some kind of exercise you are doing in order to learn, but I will post this answer so you can see how get this done using some of the C++ standar functions.
Using find function from algorithm
string test = "Hello world";
string vowels("aeiuo"); // Its much easier to define vowels than consonants.
int consonants_count = test.length(); // Assume all letters are consonants.
for (auto &c : test) // for each character in test
{
if (find(vowels.begin(), vowels.end(), c) != vowels.end()) // If c is founded inside vowels ...
{
consonants_count--; // Decrement the number of consonants.
}
}
Using regular expressions
#include <regex>
string test = "Hello world"; // A test string.
regex re("a|e|i|o|u"); // Regular expression that match any vowel.
string result = regex_replace(test, re, ""); // "Delete" vowels.
cout << result.length() << endl; // Count remaining letters.
Three problems:
You are not passing an array of consonants, you are passing a single character
You are passing an invalid character (one past the end of the consonant array)
You are counting how many times that invalid character is present.
To fix this problem, make sure that you pass an array as the second parameter, and add a nested loop to iterate that array.
your function counter if checking the input char by char and compare it to a single char(ch).
you need to run your counter function on all the chars in consonants array, or change the counter function:
int count = 0
for(int i = 0; i < 22 ; i ++)
{
count += counter(input, consonants[i])
}
now an even better way will be to count the non consonants characters and then do length-count
#include <iostream>
#include <cctype>
#include <string>
using namespace std;
int counter(char *, char);
int main()
{
const int size = 51;
char input[size];
cout << "Enter your letters." << endl;
cin >> input;
cout << consonants << "appears";
cout << counter(input) << "times" << endl;
}
int counter(char *strPtr)
{
int times = 0;
int length = 0;
const char consonants[5] = "aeoui";
while (*strPtr != '\0')
{
for(int i = 0; i < 5 ; i ++)
{
if (*strPtr == consonants[i])
times++;
strPtr++;
length++;
}
}
return length-times;
}

Encryption issue in c++

I'm currently attempting to implement a substitution cipher that for some reason keeps crashing, the code is fairly straight forward but I keep running into problems I believe originate in the for loop or when I attempt to read in the data from a file.
cout << "Ener a key :";
cin >> key;
cin.ignore();
cout << endl << "Enter input file name: ";
getline(cin,fileIn);
inputfile.open(fileIn.c_str(), ios::in);
cout << endl << "Enter output file name: ";
getline(cin,fileOut);
outfile.open(fileOut.c_str(), ios::app);
cout << endl << "[E]ncryption or [D]ecryption? :";
cin >> EorD;
//Encryption
if (EorD == "E" || "e")
{
while(!inputfile.eof()) // Reading in file data, while not end of file.
{
getline(inputfile,plainText);
}
for (int i = 0; i <= plainText.length(); i++)
{
char letter = plainText.at(i);
int val = (int)letter; // getting ascii value of each letter.
int EnVal = (val - 32) + key;
if(EnVal > 95)
{
EnVal = (EnVal - 95) + 32;
}
char EnLetter = static_cast<char>(EnVal);
outfile << EnLetter;
change
for (int i = 0; i <= plainText.length(); i++)
to
for (int i = 0; i <= plainText.length()-1; i++)
because out of range. Even better use iterator.
also change this:
if (EorD == "E" || "e")
to
if (EorD == "E" || EorD == "e")
because former is always true.
as James Kanze pointed out, don't use std::string::at, you don't need it here, change it to std::string operator[] and my advice: additionally cover your code in a nice try{}catch(...){} block
you might consider something like this:
#include <vector>
#include <iterator>
#include <algorithm>
int key=100;
char op(char c){
char letter = c;
int val = (int)letter; // getting ascii value of each letter.
int EnVal = (val - 32) + key;
if(EnVal > 95)
{
EnVal = (EnVal - 95) + 32;
}
char EnLetter = static_cast<char>(EnVal);
return EnLetter;
}
int main(){
try{
std::string s="piotrek";
std::vector<char> vc_in(s.begin(),s.end());
std::vector<char> vc_out;
std::transform (vc_in.begin(), vc_in.end(),
std::back_inserter(vc_out), op); //this do the thing
std::copy(vc_out.begin(), vc_out.end(),
std::ostream_iterator<char> (std::cout,"_")); // to print
}catch(std::exception& e){
cout<<"exception: "<<e.what();
}
return OK;
}
You are looping one index too far in the plainText string. Since it has length() entries and the first one is 0, the last index is length()-1. Try this:
for (int i = 0; i < plainText.length(); i++)
Otherwise plainText.at(i) will crash when i is too big.