Read command line from char - c++

I want to create a program capable of reading the command line in format:
SET x = ( expression ) <--- spaces between everywhere
without using strings. I wanted to cin in the command and simply compare it to a list of possible values,
so..
char a;
cin>>a;
if(a== 'SET'){
----
}
this obviously does not work because a is an array.
I thought i could do it this way (if a[0]=='S'), then check a[1] for 'E' etc. but I believe this is a widely inefficient way of doing this? or isnt it?

For your example, you can use std::string
std::string a;
cin >> a;
if (a.compare("SET"))
{
// do stuff
}
string::compare will do an equality comparison for the full string instead of character-by-character comparison.

You can use the strcmp function:
#include <iostream>
#include <cstring>
int main(int argc, char* argv[]) {
char * a;
std::cin >> a;
if (strcmp(a, "SET") == 0) {
std::cout << "check" << std::endl;
}
return 0;
}

Related

Determine if a character exists within a string? (Not using loops)

I'm trying to create a funcion that returns true if a non-alphanumeric character exists within a string. I cannot use a loop, however, and I'm looking for the right algorithm to do so.
not_alphanumeric("hello") // This would return FALSE
not_alphanumeric("h%llo") // This would return TRUE
I need to know what type of algorithm I need to use in order to do this, OR if there is some non-loop related method in order to do this.
If you don't know about the any_of() defined in algorithm library, you should take a look into it if you're making a program which contains no loops.
Consider this:
#include <iostream>
#include <algorithm>
bool checkAlphaNum(char *);
int main(void) {
char *string = new char[1024];
std::cout << "Enter a string: ";
std::cin >> string;
std::cout << checkAlphaNum(string) << std::endl;
return 0;
}
bool checkAlphaNum(char *arr) {
// verifying each character of the given string argument
return std::any_of(arr, arr + strlen(arr), [](char ch)
{return isalnum(ch);});
}

Comparing character arrays is not working

I have found a problem while trying to use "character arrays" in an if condition. It should be true with my input, but it is not.
Here is my code:
#include <iostream>
using namespace std;
int main()
{
char a[20];
cin.get(a,15, '\n'); // for input
cout << a << endl; // output
if (a == "hello world") { // checking if condition
cout << "how are you?" << endl;
}
}
You should be using std::string, not some char[].
Then the equality will work as you expect.
This char[20], strcmp nonsense is archaic and error-prone. There is no place for it here.
You need strcmp() ( include the header <cstring> ) to check equality of character arrays.
Try
if( !strcmp(a,"hello world"))
BTW, since you are on c++, it's better to use std::string, so you can easily do
std::string a;
getline( std::cin , a );
if(a=="hello world") //checking if condition
{
std::cout<<"how are you";
}

Why does isalpha() stop at spaces?

int main(){
char check[256], c;
int ch=0;
cin >> check;
while (check[ch]){
c = check[ch];
if (isalpha(c))putchar(c);
ch++;
}
}
If for example check[256] is "this and this" the program will only print "this" what means that at the first space it stops , first question is why , and second is there a way to stop it so it will print either "this and this" or "thisandthis" ?
If you had built a short example, like this:
#include <stdio.h>
#include <ctype.h>
int main()
{
char check[256] = "this and this";
int ch = 0;
while (check[ch])
{
char c = check[ch];
if (isalpha(c)) putchar(c);
ch++;
}
return 0;
}
You would have noticed this works exactly as you want it to work. So the culprit is this line:
cin >> check;
If you want to read a line, use getline:
std::getline(std::cin, check);
You should really be using
#include <iostream>
#include <string>
and stop using char arrays. You are using C++, not C.
In this line:
cin >> check;
only the first word will be read into the char array, because this is the default behavior of cin. Please verify that the array contains the entire string.
I'm surprised that no one has objected this yet. By all means not use a plain char array with std::cin. Have you considered what might happen if some user would enter a word longer than whatever your buffersize may be?
Of course, you would use std::string instead, and, of course, you would use std::getline(std::cin, s) to read a line.
Example:
#include <iostream>
#include <string>
#include <cctype>
int main() {
std::string s;
if (std::getline(std::cin, s))
for (char c : s)
if (std::isalpha(c))
std::cout << c;
std::cout << "\n";
}
Output:
$ g++ test.cc -std=c++11 && echo "Hello World" | ./a.out
HelloWorld

how to read character data using cin to store in an array and display?

I am writing a simple console application to read 3 words and keep them in an array. But after taking three inputs from the console it only displays the third word three times in the console. For example, if I give the input: "one", "two" "three" the output shows only "three" 3 times).
Here is my code:
int main(int argc, char *argv[])
{
char* input[30];
char word[30];
int i=0;
for(i=0; i<3 ;++i)
{
cin >> word;
input[i] = word;
}
input[i] = 0;
i=0;
while(input[i])
{
cout << input[i] << endl;
i++;
}
return 0;
}
What I am doing wrong here? Thanks for any help.
You only have one buffer ( char word[30] ), which you are overwriting each time.
When you do:
input[i] = word;
You're assigning the address of the first element in that one and only buffer to each element in input (arrays degrade to pointers when you use the bare name). You end up with three copies of the same address in input[] (which is address of word, which contains the last thing your read from cin)
One approach to fix this would be to use strdup() and assign the newly allocated string to your input[i]
for(i=0; i<3 ;++i)
{
cin >> word;
input[i] = strdup(word);
}
Also ... if you only are going to have three input "words" you only need an array of 3 char pointers:
char *input[3];
and your output loop would look much like your input loop:
for(i=0; i<3 ;++i)
{
cout << input[i] << endl;
}
Edit: Note that this answer was based on your wanting to use arrays. If this isn't homework that requires that, see bobbymcr's answer - when in C++, use C++.
You marked your question as "C++" (not "C") so I will recommend that you actually use C++ idioms to do this. Modern programs should not be using raw char arrays and pointers except for low level programming and interoperability with legacy or barebones C APIs.
Consider using string and vector as they will make your life much easier. Here is a reimplementation of your program using these types. Aside from the iterator stuff (which I admit is a bit strange until you get used to it), it should seem a lot clearer than the equivalent using char *, etc.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main(int argc, char ** argv)
{
vector<string> input;
for (int i = 0; i < 3; ++i)
{
string word;
cin >> word;
input.push_back(word);
}
for (vector<string>::const_iterator it = input.cbegin(); it != input.cend(); ++it)
{
cout << *it << endl;
}
return 0;
}
The problem is here:
char* input[30];
You maybe tempted to think that this is array of character array, but in essence it's not.
You would either need to dynamically allocate space for the array, or simply use two dimensional character array(fixing the max number of words that you can have).
char input[30][30]; // maximum 30 words having at most 29 characters each

Counting occurrences of letter in a file

I'm trying to count the number of times each letter appears in a file. When I run the code below it counts "Z" twice. Can anyone explain why?
The test data is:
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
#include <iostream> //Required if your program does any I/O
#include <iomanip> //Required for output formatting
#include <fstream> //Required for file I/O
#include <string> //Required if your program uses C++ strings
#include <cmath> //Required for complex math functions
#include <cctype> //Required for letter case conversion
using namespace std; //Required for ANSI C++ 1998 standard.
int main ()
{
string reply;
string inputFileName;
ifstream inputFile;
char character;
int letterCount[127] = {};
cout << "Input file name: ";
getline(cin, inputFileName);
// Open the input file.
inputFile.open(inputFileName.c_str()); // Need .c_str() to convert a C++ string to a C-style string
// Check the file opened successfully.
if ( ! inputFile.is_open())
{
cout << "Unable to open input file." << endl;
cout << "Press enter to continue...";
getline(cin, reply);
exit(1);
}
while ( inputFile.peek() != EOF )
{
inputFile >> character;
//toupper(character);
letterCount[static_cast<int>(character)]++;
}
for (int iteration = 0; iteration <= 127; iteration++)
{
if ( letterCount[iteration] > 0 )
{
cout << static_cast<char>(iteration) << " " << letterCount[iteration] << endl;
}
}
system("pause");
exit(0);
}
As others have pointed out, you have two Qs in the input. The reason you have two Zs is that the last
inputFile >> character;
(probably when there's just a newline character left in the stream, hence not EOF) fails to convert anything, leaving a 'Z' in the global 'character' from the previous iteration. Try inspecting inputFile.fail() afterwards to see this:
while (inputFile.peek() != EOF)
{
inputFile >> character;
if (!inputFile.fail())
{
letterCount[static_cast<int>(character)]++;
}
}
The idiomatic way to write the loop, and which also fixes your 'Z' problem, is:
while (inputFile >> character)
{
letterCount[static_cast<int>(character)]++;
}
There are two Q's in your uppercase string. I believe the reason you get two counts for Z is that you should check for EOF after reading the character, not before, but I am not sure about that.
Well, others already have pointed out the error in your code.
But here is one elegant way you can read the file and count the letters in it:
struct letter_only: std::ctype<char>
{
letter_only(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table()
{
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::space);
std::fill(&rc['A'], &rc['z'+1], std::ctype_base::alpha);
return &rc[0];
}
};
struct Counter
{
std::map<char, int> letterCount;
void operator()(char item)
{
if ( item != std::ctype_base::space)
++letterCount[tolower(item)]; //remove tolower if you want case-sensitive solution!
}
operator std::map<char, int>() { return letterCount ; }
};
int main()
{
ifstream input;
input.imbue(std::locale(std::locale(), new letter_only())); //enable reading only leters only!
input.open("filename.txt");
istream_iterator<char> start(input);
istream_iterator<char> end;
std::map<char, int> letterCount = std::for_each(start, end, Counter());
for (std::map<char, int>::iterator it = letterCount.begin(); it != letterCount.end(); ++it)
{
cout << it->first <<" : "<< it->second << endl;
}
}
This is modified (untested) version of this solution:
Elegant ways to count the frequency of words in a file
For one thing, you do have two Q's in the input.
Regarding Z, #Jeremiah is probably right in that it is doubly counted due to it being the last character, and your code not detecting EOF properly. This can be easily verified by e.g. changing the order of input characters.
As a side note, here
for (int iteration = 0; iteration <= 127; iteration++)
your index goes out of bounds; either the loop condition should be iteration < 127, or your array declared as int letterCount[128].
Given that you apparently only want to count English letters, it seems like you should be able to simplify your code considerably:
int main(int argc, char **argv) {
std::ifstream infile(argv[1]);
char ch;
static int counts[26];
while (infile >> ch)
if (isalpha(ch))
++counts[tolower(ch)-'a'];
for (int i=0; i<26; i++)
std::cout << 'A' + i << ": " << counts[i] <<"\n";
return 0;
}
Of course, there are quite a few more possibilities. Compared to #Nawaz's code (for example), this is obviously quite a bit shorter and simpler -- but it's also more limited (e.g., as it stands, it only works with un-accented English characters). It's pretty much restricted to the basic ASCII letters -- EBCDIC encoding, ISO 8859-x, or Unicode will break it completely.
His also makes it easy to apply the "letters only" filtration to any file. Choosing between them depends on whether you want/need/can use that flexibility or not. If you only care about the letters mentioned in the question, and only on typical machines that use some superset of ASCII, this code will handle the job more easily -- but if you need more than that, it's not suitable at all.