I'm writing a function for a program that allows a student to copy a template text file. This function checks the user's input to see if his desired template is allowed for his class.
I'm getting the error "Comparison with string literal results in unspecified behavior" on lines 21 and 25. I have done "cout << name" to verify that variable is storing correctly, which it is, so I know that's not the problem.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
//TEMPLATE CHECK
//First you check to see if the student is allowed to use the template
int templateCheck()
{
//Declare file name variable
char name[256];
//Prompt for user input
cout << "Enter file name: ";
//Cin user input
cin >> name;
//Begin check
//CS221 is the first template you can't use
if(name == "/home/cs221Temp.txt")
cout << "You are not allowed to use CS221 templates./n";
//CS 321 is the other template you can't use
else if (name == "/home/cs321Temp.txt")
cout << "You are not allowed to use CS321 templates./n";
//Any others are okay (I commented these out since I'm just working on this function by itself)
//else
//copyTemplate();
return 0;
}
This statement
if(name == "/home/cs221Temp.txt")
compares for pointers being equal (which is unlikely), not their contents.
What you actually want is
if(strncmp(name,"/home/cs221Temp.txt",256) == 0)
or
std::string name;
in your function.
You can't compare two C-style strings by ==ing them. (C-style string literals just give you a pointer to the first character in a sequence of characters in RAM, ended by a 0 valued character, so you'd be comparing addresses instead of strings).
What you want to use would be the strcmp function from stdlib.
However, you're writing C++, not C.
So, I recommend using the string class, which has an overloaded == operator, so you can do
if (string1 == string2)
In C/C++ (unlike in "similar" languages like JavaScript) when you use == on "strings" you are comparing pointers.
If you want to compare the strings' content, then you must use functions that are designed for that purpose. Like strcmp() from the standard C library
Related
I wanted to declare an array with a pointer in character type, and the length of the array can be determined by my input string.
I wrote it in this way:
char *s;
cout << "Enter a string: " << endl;
cin >> s;
I expected that I can initialize the string by the cin operation, but an error showed up when compiling. The error is about "invalid operands to binary expression".
I'm not sure why the lines I wrote was wrong.
I though not only the built in string class is used for declaring an array.
Isn't the string data type in C++ the same as "a character array"?
Isn't the line char *s means the pointer s points to an character array (or string)?
Thank you!
You should use std::string.
It is a class that represents a string of characters. It is different than an old c style array of characters (although internally might contain one).
In your case:
#include <string>
#include <iostream>
std::string s;
std::cout << "Enter a string: " << endl;
std::cin >> s;
Using std::string means memory is managed automatically for you. Specifically with cin it will also be resized to fit the input.
A side note: better to avoid using namespace std - see here Why is "using namespace std;" considered bad practice?.
"the cin operation".
cin is really the source. The real work is done by the overloaded operator>>. And the operator>> which reads to a char* expects that the char* is already allocated to the right size. That's of course a problem with cin, where the size is unknown.
The operator>> overload that reads to std::string will resize the std::string to the right size.
The answer to your question is no, as when you create a type pointer you always have to specify in advance how much memory to allocate. We can imagine that this is what happens with strings, that is to go to fetch the data and arrange the occupied cells in memory at a later time.
Now the real problem is, it is true that you have declared a pointer to a character, but you have not specified how much to allocate for it. It is as if you are saying you want to create a box but you are not specifying the size. I show you the correct method:
char *s = new char[10];
Obviously when using pointers, always remember to deallocate them at the end of use so as not to have any memory leaks.
Taking a summary of the situation, you tried to save a data in a box that you intend to create but does not exist. That is, you have named the box called s which will contain a pointer to a character but you have not yet built/created it in its final size.
This question already has answers here:
Comparing character arrays and string literals in C++
(4 answers)
Closed 1 year ago.
just learning C++ here.
#include <iostream>
#include <string>
int main()
{
char name[1000];
std::cout << "What is your name?\n";
std::cin.get(name, 50);
name == "Shah Bhuiyan" ? std::cout << "Okay, it's you\n" : std::cout<< "Who is this?\n";
}
So here I wrote a program where I created a variable name[100]. I use the cin iostream object thing to take input for the variable name. If the name is equal to my name (as seen in name == "Shah Bhuiyan" :) then output the first thing or output 'Who are you?'
Instead of outputting 'Oh, it's you' it outputs 'who is this?'
Why doesn't this work?
Your code is using arrays of characters. Any comparisons using == will compare their memory address. Since name and "Shah Bhuiyan" are two distinct arrays of characters, it will always be false.
The obvious solution is to use c++ strings from the standard library:
#include <iostream>
#include <string>
int main()
{
std::string name;
std::cout << "What is your name?\n";
std::getline(std::cin, name);
name == "Shah Bhuiyan" ? std::cout << "Okay, it's you\n" : std::cout<< "Who is this?\n";
}
The std::string type has operators defined that do the right thing here, and will compare the values of each.
Arrays do not have the comparison operator.
In fact in this expression
name == "Shah Bhuiyan"
there are compared two pointers (due to the implicit conversion of array designators to pointers to their first elements): the first one is a pointer to the first character of the character array name and the second one is a pointer to the first character of the string literal.
As the array and the string literal occupy different extents of memory the comparison of the addresses will always evaluate to false.
You need to use the standard C string function strcmp to compare two strings.
#include <cstring>
//...
std::strcmp( name, "Shah Bhuiyan" ) == 0 ? std::cout << "Okay, it's you\n" : std::cout<< "Who is this?\n";
If you want to use the equality operator == then instead of the character array use an object of the type std::string.
You could use std::getline to read into std::string instead of C-style char buffer.
Hi i'm having trouble making a function that checks the data type of a variable and checks it to make sure if a data type is similar to it in C++. Here's my code so far:
#include <iostream>
#include <typeinfo>
using namespace std;
int main() {
int typeCheck(string words, string typeWanted);
//make number assurance function .
string word;
cin >> word;
typeCheck(word, "string");
}
int typeCheck(string words, string typeWanted) {
if (typeid(words).name() != typeid(typeWanted).name()) {
cin.clear();
cin.ignore();
return 0;
}
else if (typeid(words).name()== typeid(typeWanted).name())
cout << "All good";
}
When I run the code it keeps saying the same output which is: All good even if I put a string or an int when its not the correct one. Instead of saying this I want it to clear the buffer and ignore it. Can anyone help me with this problem? Thanks in advance!
C++ is a statically typed language, meaning that the type is known at compile time. It will never be known only at run time.
What that means is that in your example:
int typeCheck(string words, string typeWanted);
both words and typeWanted will always be strings. If it is ever not a string, it will fail to compile. Thus, using typeid() in this situation is somewhat pointless. Your if statement will always be false, and your else-if statement will always be true.
Instead, you would want to use typeid() when you don't know they will be the same type, like in some sort of template situation:
template <class WordsType, class TypeWantedType>
int typeCheck(WordsType words, TypeWantedType typeWanted);
Here, a typeid() comparison makes more sense, because you don't really know if words and typeWanted are both strings.
You could do something like this instead:
template <class WordsType>
int typeCheck(WordsType words, string typeWanted) {
if (typeid(words).name() != typeWanted) {
//...
}
// ...
}
This would compare an unknown type to a wanted type.
Finally, there is another option, #RSahu's option from the comments:
if(words == typeWanted) {
//...
}
This will compare the input the user gave to the string "string".
It's unclear to me what you want to do exactly, so I can't recommend which one you should use, but at least now you have a couple of options.
It is because you are converting the type to string eaither way so it will allways trigger as correct as long as it is a string in the function input.
I would recommend that you use a template type so that whatever you enter into the TypeCheck() function will retain its type.
I meant to write program which will simply delete single letters from the input given by user, let's say we've got some text like: "monkey eat banana" and we supposed to delete the letter 'a' from the text above.
The final output supposed to look like this:
'monkey et bnn'
I've got the code which works pretty much flawlessly with single strings, but I have to use getline() function to obtain some longer texts, that is why I have to declare array of string, in order to pass it's size in the second argument of getline() function, like so:
string text[256];
getline(text, 256);
I would like to use getline() function without giving a size of an array, but I think it's impossible, therefore I need to stick with string array instead of a string.
The problem I've got is that I don't know how to correctly pass array of string, to use it as function's argument. Here's my code;
#include <iostream>
#include <string>
using namespace std;
void deleteLetter(string &text[], char c)
{
size_t positionL = text.find(c);
if(positionL == string::npos)
cout << "I'm sorry, there is no such letter in text" << endl;
else
text.erase(positionL, positionL);
cout << "After your character removed: " << text << endl;
}
int main()
{
string str1[256];
char a = 'a';
cin.getline(str1, 256);
deleteLetter(str1, a);
}
I know it's elementary stuff, but still I can't figure it out on my own.
Perhpahs I should reach out for your help.
It sounds to me like you don't need an array of strings. Just to read as many characters the user types, into a string. getline should deal fine with this.
int main()
{
std::string str1; // just a string here, not an array.
std::getline (std::cin,str1);
deleteLetter(str1, 'a');
}
Now you should change the signature of DeleteLetter to take a single string as argument.
void deleteLetter(std::string& text, char c);
How your are going to implement deleteLetter is another question. The way you have it, it will delete only the first occurence of 'a'.
To read a string from console input (cin), you can use the getline() function:
std::string line;
std::getline(std::cin, line);
To remove all the occurrences of a given letter from a string, you can use the so called erase-remove idiom, with a combination of the string::erase() method and the std::remove() algorithm.
(Note that this idiom is usually showed applied to std::vector, but don't forget that a std::string can also be viewed as a "container of characters" stored in sequence, similar to vector, so this idiom can be applied to string content as well.)
To pass a std::string to functions/methods, use the usual C++ rules, i.e.:
If the function is observing the string (without modifying it), pass using const reference: const std::string &
If the function does modify the content of the string, you can pass using non-const reference: std::string &
A simple compilable code follows:
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
//
// NOTE:
// Since the content of 'text' string is changed by the
// removeLetter() function, pass using non-const reference (&).
//
void removeLetter(string& text, char letter)
{
// Use the erase-remove idiom
text.erase(remove(text.begin(), text.end(), letter),
text.end());
}
int main()
{
string line;
getline(cin, line);
cout << "Read string: " << line << endl;
removeLetter(line, 'a');
cout << "After removing: " << line << endl;
}
This is what I got with MSVC:
C:\Temp\CppTests>cl /EHsc /W4 /nologo test.cpp
test.cpp
C:\Temp\CppTests>test.exe
monkey eats banana
Read string: monkey eats banana
After removing: monkey ets bnn
It's not very clear to me from your question if you also want to pass vectors of strings around (probably in other parts of your code)...
Anyway, if you want a vector of strings (i.e. you want to store some strings in a vector container) you can simply combine these STL class templates like this:
std::vector<std::string> strings;
To pass that to functions/methods, use the usual C++ rules, i.e.:
If the function is observing the array of strings (without modifying it), pass using const references (const &): vector<string> &
If the function does modify the content of the vector, you can pass using non-const references (&): vector<string> &
I am having a C++ console application code, which would look up for the condition and then save the text to the (.txt) file.
But the condition is not being applied here. What I have in condition is this:
char command[100];
cin >> command;
if (command == "save") {
fstream file;
file.open("C:\\Users\\AfzaalAhmad\\Documents\\text.txt");
file << "Data you provided was as saved!";
cout << "File Saved!";
}
else {
cout << "Ummm, sir I think there is an error!\n" <<
"The command you entered was: " << command;
}
What I am doing is, to check the command provided by the user, if the command is 'save'
if(command == "save")
then save the data to a file, in the file the data is present when I use this code:
if(command != "save")
Because the command doesnot have to be save, the code executes and gives me the data in the file that is in documents folder.
However, if the else block gets executed, I can still see the correct command 'save' at the end, which is being shown by the code as you can see in the code block.
You can see there, I am using the correct command, but it is not executing as if(command == "save") but it executing if I use this code if(command != "save").
Any guidance please?
command and the string literal "save" are both arrays of chars. They are both being converted to pointers to the first elements (this is called array-to-pointer conversion) and you are comparing those pointers. So what you're really doing with command == "save" is checking if their first characters have the same address.
Instead, to compare C-style strings like you want (checking if all characters in the strings are the same), you need to use std::strcmp. However, a much more preferable solution in C++ is to make command a std::string, instead of an array of char. std::string supports comparison using ==.
In this condition
if (command == "save")
you are trying to compare character arrays. But neither C nor C++ has the comparison operator for arrays. Instead this the string literal and the array in the left part of the operation are implicitly converted to pointers to their first characters and in fact you are comparing two pointers that will be always unequal.
To compare character arrays you should use standard C function std::strcmp that is declared in header <cstring>( in C++ ) or <string.h> (in C)
For example
if ( std::strcmp( command, "save" ) == 0 )
command is a char array, you cannot compare it to a string literal like that (you are actually comparing adresses). If you don't want to use std::string that overload the == operator you could say
strcmp(command, "save"); // it returns zero if equal
Because you should use strcmp to compare C style strings. Or use std::string, which is also better in many other ways, besides being able to compare strings with ==.
A C style string constant is just the address to some memory that holds that particular string, so when you compare command == "save", then for that comparison to be true, command must have the same address as the constant string "save" - which clearly isn't the case ever.
You are comparing the address of command to the address of a string literal. They will never be the same.
Possible solutions:
use the C library function strcpy: if (0 == strcmp(command, "save"))
cast one to a C++ string: if (std::string(command) == "save)
Use a C++14 string literal: if (command == "save"s)
Store the user's input into a C++ string to begin with.
The last of these is the best option, and looks like:
std::string command;
cin >> command;
if (command == "save") {
The variable command is of type char*, because an array in C/C++ is (basically) a pointer (and a fixed maximum array size). Since you are using C++, consider using std::string instead: http://www.cprogramming.com/tutorial/string.html.
What you are using is a C-Style string, and you have to use functions such as strcmp, for example described here: How do I properly compare strings?. But that is the C-way, and, if you're writing C++, you should stick to the std::string class for such purposes.
For comparing c-strings you should use strcmp() function.