Scanf function with strings - c++

I need to read input from user. The input value may be string type or int type.
If the value is int then the program insert the value into my object.
Else if the value is string then it should check the value of that string, if it's "end" then the program ends.
Halda h; //my object
string t;
int tint;
bool end=false;
while(end!=true)
{
if(scanf("%d",&tint)==1)
{
h.insert(tint);
}
else if(scanf("%s",t)==1)
{
if(t=="end")
end=true;
else if(t=="next")
if(h.empty()==false)
printf("%d\n",h.pop());
else
printf("-1\n");
}
}
The problem is that scanning string doesn't seem to work properly.
I've tried to change it to: if(cin>>t) and it worked well.
I need to get it work with scanf.

The specifier %s in the scanf() format expects a char*, not a std::string.
From C11 Standard (C++ Standard refers to it about the C standard library):
Except in the case of a % specifier, the input item (or, in the case of a %n directive, the
count of input characters) is converted to a type appropriate to the conversion specifier. If
the input item is not a matching sequence, the execution of the directive fails: this
condition is a matching failure. Unless assignment suppression was indicated by a *, the
result of the conversion is placed in the object pointed to by the first argument following
the format argument that has not already received a conversion result. If this object
does not have an appropriate type, or if the result of the conversion cannot be represented
in the object, the behavior is undefined.
Anyway, here there's is no real reason to prefer the C way, use C++ facilities. And when you use the C library, use safe functions that only reads characters up to a given limit (just like fgets, or scanf with a width specifier), otherwise you could have overflow, that leads again to undefined behavior, and some errors if you're luck.

That's a really bad way to check for end-of-input. Either use an integer or use a string.
If you choose string, make provisions to convert from string to int.
My logic would be to first check if it can be converted to integer. if it can be, then continue with the logic. If it can't be(such as if it's a float or double or some other string) then ignore and move on. If it can be, then insert it into Halda's object.
Sidenote: Do not use scanf() and printf() when you're working with C++.

Assuming string refers to std::sring this program doesn't have defined behavior. You can't really use std::string with sscanf() You could set up a buffer inside the std::string and read into that but the string wouldn't change its size. You are probably better off using streams with std::string (well, in my opinion you are always better off using streams).

Related

Coverity issue: Copy of overlapping memory (OVERLAPPING_COPY) on sprintf statement

char arr[512];
...
sprintf(arr, "%s %30s", arr, "Some Text");
I'm getting the following message for the sprintf statement:
In the call to function sprintf, the arguments arr and arr may point to the same object.
Is there another way to implement this kind of formatting?
This code code contains two unrelated errors. As for the PVS-Studio analyzer, it issues two following warnings:
V576 Incorrect format. A different number of actual arguments is expected while calling 'sprintf' function. Expected: 4. Present: 3. test.cpp 54
V541 It is dangerous to print the 'arr' string into itself. test.cpp 54
The first one implies that the function is passed insufficient number of actual arguments. Indeed, the format string indicates that a string and an integer number are expected as arguments. But only a string is passed. There is no numeric argument, resulting in the usage of an amount of memory with a random value and consequently undefined behavior.
The second warning tells us that there is no guarantee that the sprintf function works correctly if one buffer is used as an input and output buffer. Such code might work correctly or it might not. It all depends on the implementation of the sprintf function. In any case, there is no reason to write code in such a way.
Therefore, Coverity is absolutely right when issuing the warning for this code. The code is definitely incorrect.
P.S. It reminded me of another funny case related to the usage of a "fake sprintf" :).
The overlapping warning has to do with the fact that you are copying arr to itself, thus overwriting it's content.
Furthermore in the code:
sprintf(arr, "%s %0x", arr);
^^^
%s takes the arr string, but %0x doesn't take an unsigned hexadecimal integer variable as it should, so you are probably missing a parameter.
Something along the lines of:
char arr[512];
char arr2[1024];
unsigned int x = 15;
sprintf(arr2, "%s %0x", arr, x);

Can std::string::c_str() be used whenever a string literal is expected?

I would guess that the last two lines in this code should compile.
#include "rapidjson/document.h"
int main(){
using namespace rapidjson ;
using namespace std ;
Document doc ;
Value obj(kObjectType) ;
obj.AddMember("key", "value", doc.GetAllocator()) ; //this compiles fine
obj.AddMember("key", string("value").c_str(), doc.GetAllocator()) ; //this does not compile!
}
My guess would be wrong, though. One line compiles and the other does not.
The AddMember method has several variants as documented here, but beyond that... why is the return of .c_str() not equivalent to a string literal?
My understanding was that where ever a string literal was accepted, you could pass string::c_str() and it should work.
PS: I'm compiling with VC++ 2010.
EDIT:
The lack of #include <string> is not the problem. It's already included by document.h
This is the error:
error C2664: 'rapidjson::GenericValue<Encoding> &rapidjson::GenericValue<Encoding>::AddMember(rapidjson::GenericValue<Encoding> &,rapidjson::GenericValue<Encoding> &,Allocator &)'
: cannot convert parameter 1 from 'const char [4]' to 'rapidjson::GenericValue<Encoding> &'
with
[
Encoding=rapidjson::UTF8<>,
Allocator=rapidjson::MemoryPoolAllocator<>
]
and
[
Encoding=rapidjson::UTF8<>
]
EDIT2:
Please ignore the fact that .c_str() is called on a temporal value. This example is just meant to show the compile error. The actual code uses a string variable.
EDIT3:
Alternate version of the code:
string str("value") ;
obj.AddMember("key", "value", doc.GetAllocator()) ; //compiles
obj.AddMember("key", str, doc.GetAllocator()) ; // does not compile
obj.AddMember("key", str.c_str(), doc.GetAllocator()) ; // does not compile
The std::string::c_str() method returns a char const*. The type of a string literal is char const[N] where N is the number of characters in the string (including the null terminator). Correspondingly, the result of c_str() can not be used in all places where a string literal can be used!
I'd be surprised if the interface you are trying to call requires a char array, though. That is, in your use it should work. It is more likely that you need to include <string>.
even if this code compiled:
obj.AddMember("key2", string("value").c_str(), doc.GetAllocator());
You cannot guarantee that it is safe.
The const char* returned by std::string::c_str() will be valid until the end of this statement.
If the AddMember method stores a copy of the string itself, all well and good. If it stores a pointer then you're doomed. You need knowledge of the inner workings of AddMember before you can reason about the correctness of your code.
I suspect the authors have already thought of this and have constructed overloads that demand that you either send in a std::string object (or equivalent) or a string literal reference (template<std::size_t N> void AddMember(const char (&str)[N]))
Even if this is not what they had in mind, they might be looking to protect you from yourself, in case you inadvertently send in an invalid pointer.
While seemingly an inconvenience, this compile time error indicates a possibly-faulty program. It's a tribute to the library's authors. Because compile time errors are a gazillion times more useful than runtime errors.
Looking at the documentation you linked to, it seems like you are trying to call the overload of AddMember taking two StringRefTypes (and an Allocator). StringRefType is a typedef for GenericStringRef<Ch>, which has two overloaded constructors taking a single argument:
template<SizeType N>
GenericStringRef(const CharType(&str)[N]) RAPIDJSON_NOEXCEPT;
explicit GenericStringRef(const CharType *str);
When you pass a string literal, the type is const char[N], where N is the length of the string + 1 (for the null terminator). This can be implicitly converted to a GenericStringRef<Ch> using the first constructor overload. However, std::string::c_str() returns a const char*, which cannot be converted implicitly to a GenericStringRef<Ch>, because the second constructor overload is declared explicit.
The error message you get from the compiler is caused by it choosing another overload of AddMember which is a closer match.
Re
” why is the return of .c_str() not equivalent to a string literal
A string literal is a zero-terminated string in an array with size known at compile time.
c_str() produces a pointer to (the first item in) a zero-terminated string in an array with size known only at run-time.
Usually a string literal expression will be used in a context where the expression decays to pointer to first item, but in some special cases it does not decays. These cases include
binding to a reference to array,
using the sizeof operator, and
forming a larger literal by compile time concatenation of string literals (simply writing them in order).
I think that's an exhaustive list.
The error message you cite,
” cannot convert parameter 1 from 'const char [4]' to 'rapidjson::GenericValue &
… does not match your presented code
#include "rapidjson/document.h"
int main(){
using namespace rapidjson ;
using namespace std ;
Document doc ;
Value obj(kObjectType) ;
obj.AddMember("key1", "value", doc.GetAllocator()) ; //this compiles fine
obj.AddMember("key2", string("value").c_str(), doc.GetAllocator()) ; //this does not compile!
}
Nowhere in this code is there a three character long string literal.
Hence the claims that “this compiles” and “this does not compile”, are not very trustworthy.
You
should have quoted the actual error message and actual code (at least one of them is not what you had when you compiled), and
should have quoted the documentation of the function you're calling.
Also, note that the actual argument that compiler reacts to in the quoted diagnostic, is a literal or an array declared as such, not a c_str() call.

Disambiguating std::isalpha() in C++

So I am currently writing a part of a program that takes user text input. I want to ignore all input characters that are not alphabetic, and so I figured std::isalpha() would be a good way to do this. Unfortunately, as far as I know there are two std::isalpha() functions, and the general one needs to be disambiguated from the locale-specific one thusly:
(int(*)(int))std::isalpha()
If I don't disambiguate, std::isalpha seems to return true when reading uppercase but false when reading lowercase letters (if I directly print the returned value, though, it returns 0 for non-alpha chars, 1 for uppercase chars, and 2 for lowercase chars). So I need to do this.
I've done so in another program before, but for some reason, in this project, I sometimes get "ISO C++ forbids" errors. Note, only sometimes. Here is the problematic area of code (this appears together without anything in between):
std::cout << "Is alpha? " << (int(*)(int))std::isalpha((char)Event.text.unicode) << "\n";
if ( (int(*)(int))std::isalpha((char)Event.text.unicode) == true)
{
std::cout << "Is alpha!\n";
//...snip...
}
The first instance, where I send the returned value to std::cout, works fine - I get no errors for this, I get the expected values (0 for non-alpha, 1 for alpha), and if that's the only place I try to disambiguate, the program compiles and runs fine.
The second instance, however, throws up this:
error: ISO C++ forbids comparison between pointer and integer
and only compiles if I remove the (int(*)(int)) snippet, at which point bad behavior ensues. Could someone enlighten me here?
You are casting the return value of the std::alpha() call to int(*)(int), and then compare that pointer to true. Comparing pointers to boolean values doesn't make much sense and you get an error.
Now, without the cast, you compare the int returned by std::alpha() to true. bool is an integer type, and to compare the two different integer types the values are first converted to the same type. In this case they are both converted to int. true becomes 1, and if std::isalpha() returned 2 the comparison ends up with 2 != 1.
If you want to compare the result of std::alpha() against a bool, you should cast that returned in to bool, or simply leave out the comparison and use something like if (std::isalpha(c)) {...}
There is no need to disambiguate, because the there is no ambiguity in a normal call.
Also, there is no need to use the std:: prefix when you get the function declaration from <ctype.h>, which after C++11 is the header you should preferably use (i.e., not <cctype>) – and for that matter also before C++11, but C++11 clinched it.
Third, you should not compare the result to true.
However, you need to cast a char argument to unsigned char, lest you get Undefined Behavior for anything but 7-bit ASCII.
E.g. do like this:
bool isAlpha( char const c )
{
typedef unsigned char UChar;
return !!isalpha( UChar( c ) );
}

C++ String to Double parsing with exceptions?

In java, if I wanted to create some application which could receive both doubles and strings as appropriate input, I would probably do the following:
String input = getInput();//
try {
double foo = Double.valueOf(input);
//Do stuff with foo here
} catch (NumberFormatException e) {
//Do other validation with input
}
How would you go about doing that in c++? atof() returns 0.0 for invalid input, but how would you differentiate that from a valid double of "0.0"? As an aside, I can only include <iostream>, <string>, <cstdlib>, and <cassert> in this project. I'm assuming I need to use cin in some way, but how can you grab the original input after cin fails to parse some string as a double?
Edit: I could probably use the following, but as I said before, I'm not allowed to import <sstream> on this assignment for some reason
string input;
getline(cin, input);
double x;
istringstream foo(input);
foo >> x
if(cin){
//do manipulations with x
}
else{
//since it's not a number, check if input is a valid command etc..
}
Exceptions should be reserved for exceptional situations. While you certainly can abuse them like this, it's a lousy idea -- clearly you're pretty much expecting things other than doubles, so treating it as an exception doesn't make any real sense.
The only real question is the exact circumstance under which you want the input treated as a string. Just for example, if the input string was something like "1.23e2 non-numeric data", do you want to just use the "1.23e2" as a number, or do you want to treat the whole thing as a string?
Either way, you'd want to us strtod for the conversion -- the difference is only how you react to what it returns. In particular, strtod takes two parameters instead of just one like atof does. The second parameter is a pointer to pointer to char. Assuming you pass a non-NULL pointer, strtod will set it to point at the last character in the input string that it successfully converted. If it's pointing to the beginning of the input string, nothing was converted. If it's pointing to the end, everything was converted. If it's somewhere in between, part of the string converted, and part didn't.
For the moment, I'm going to assume that you want a double value holding whatever number could be converted at the beginning of the string, and whatever couldn't be converted treated as a string:
#include <stdlib.h>
#include <stdio.h>
int main() {
char input[] = "12.34 non-numeric data";
char *string;
double value = strtod(input, &string);
printf("Number: %f\tstring: %s\n", value, string);
return 0;
}
C++ streams associate the good, bad and fail state flags. These are stored in ios_base::goodbit, ios_base::badbit and ios_base::failbit respectively, but are commonly accessed through ios::good(), ios::bad() and ios::fail(). There's also ios_base::eofbit and ios::eof() but let's ignore that for the moment.
If parsing fails then the bad bit raises. Also, stream objects are convertible to a boolean-compatible type. If a stream is in a good state, then the statement
if( stream )
evaluates stream as true. Otherwise, it evaluates it as false. With this at hand, grabbing a value from standard input boils down to this:
#include <iostream>
// ...
double d = 0;
if ( std::cin >> d ) {
// input is a double. handle that here.
} else {
// input isn't a double. handle that here.
}
try "strtod" in stdlib.h
The C++ standard library seems to avoid exceptions for a lot of things that people might expect them, and this may not be the answer that you want to hear but parsing doubles isn't exactly rocket science so maybe it'd be ok to do it "by hand"?
One note if you do this, you'll probably want to collect it into an integer and then convert to a double and divide by 10^number_of_digits_after_decimal_point.
You could have a look at boost::lexical_cast, which would allow you to write pretty much the equivalent of the Java code:
string input;
getline(cin, input);
try {
double x = boost::lexical_cast<double>(input);
//Do manipulations with x
} catch (boost::bad_lexical_cast &) {
//Do other validation with input
}

printf("... %c ...",'\0') and family - what will happen?

How will various functions that take printf format string behave upon encountering the %c format given value of \0/NULL?
How should they behave? Is it safe? Is it defined? Is it compiler-specific?
e.g. sprintf() - will it crop the result string at the NULL? What length will it return?
Will printf() output the whole format string or just up to the new NULL?
Will va_args + vsprintf/vprintf be affected somehow? If so, how?
Do I risk memory leaks or other problems if I e.g. shoot this NULL at a point in std::string.c_str()?
What are the best ways to avoid this caveat (sanitize input?)
Any function that takes a standard C string will stop at the first null, no matter how it got there.
When you use the %c in a format and use 0 for the character value, it will insert a null into the output. printf will output the null as part of the output. sprintf will also insert the null into the result string, but the string will appear to end at that point when you pass the output to another function.
A std::string will happily contain a null anywhere within its contents, but when you take the c_str method to pass it to a function see the above answer.
What happens when you output a NUL depends on the output device.
It is a non printing character, i.e. isprint('\0') == 0; so when output to a display device, it has no visible affect. If redirected to a file however (or if calling fprintf()), it will insert a NUL (zero byte) into the file; the meaning of that will depend on how the file is used.
When output to a C string, it will be interpreted as a string terminator by standard string handling functions, although any other subsequent format specifiers will still result in data being placed in the buffer after the NUL, which will be invisible to standard string handling functions. This may still be useful if ultimately the array is not to be interpreted as a C string.
Do I risk memory leaks or other problems if I e.g. shoot this NULL at a point in std::string.c_str()?
It is entirely unclear what you mean by that, but if you are suggesting using the pointer returned by std::string.c_str() as the buffer for sprintf(); don't! c_str() returns a const char*, modifying the string through such a pointer is undefined. That however is a different problem, and not at all related to inserting a NUL into a string.
What are the best ways to avoid this caveat (sanitize input?)
I am struggling to think of a circumstance where you could "accidentally" write such code, so why would you need to guard against it!? Do you have a particular circumstance in mind? Even though I find it implausible, and probably unnecessary, what is so hard about:
if( c != 0 )
{
printf( "%c", c ) ;
}
or perhaps more usefully (since there are other characters you might want to avoid in the output)
if( isgraph(c) || isspace(c) )
{
printf( "%c", c ) ;
}
which will output only visible characters and whitespace (space, '\t','\f','\v','\n','\r').
Note that you might also consider isprint() rather than isgraph(c) || isspace(c), but that excludes '\t','\f','\v','\n' and '\r'
printf() and sprintf() will continue past a '\0' character inserted with %c, because their output is defined in terms of the content of the format string, and %c does not denote the end of the format string.
This includes their count; thus:
sprintf(x, "A%cB", '\0')
must always return 3 (although strlen(x) afterwards would return 1).