So I have two hex strings - "3b101c091d53320c000910" and "071d154502010a04000419". When I use strtol() on them I get same value for both strings.
I tried the following code-
string t1="3b101c091d53320c000910";
long int hext1=strtol(t1.c_str(),0,16);
string t2="071d154502010a04000419";
long int hext2=strtol(t2.c_str(),0,16);
cout<<hext1<<endl;
cout<<hext2<<endl;
Both are giving me same value: 9223372036854775807.
I dont know how strtol() works exactly since I am new to C++ but it's giving me same value for two different hex strings. Why?
You should start by reading the manual page. It's returning LONG_MAX since you're input is too large to fit in a long.
Also, strtol() is a very C way of doing things, and you're programming in C++.
You're not using strtol correctly. You should set errno to
0 before calling it, and check that it is still 0 after;
otherwise, it will contain an error code (which can be displayed
using strerror). Also, you should pass it the address of
a char const*, so that you can ensure that it has processed
the entire string (otherwise, "abc" will return 0, without an
error):
errno = 0;
char const* end;
long hext1 = strtol( t1.c_str(), &end, 16 );
if ( errno != 0 || *end != '\0' ) {
// Error occured.
}
Related
I'm trying to understand why a segmentation fault (SIGSEGV) occurs during the execution of this piece of code. This error occurs when testing the condition specified in the while instruction, but it does not occur at the first iteration, but at the second iteration.
LPTSTR arrayStr[STR_COUNT];
LPTSTR inputStr;
LPTSTR str;
// calls a function from external library
// in order to set the inputStr string
set_input_str(param1, (char*)&inputStr, param3);
str = inputStr;
while( *str != '\0' )
{
if( debug )
printf("String[%d]: %s\n", i, (char*)str);
arrayStr[i] = str;
str = str + strlen((char*)str) + 1;
i++;
}
After reading this answer, I have done some research on the internet and found this article, so I tried to modify the above code, using this piece of code read in this article (see below). However, this change did not solve the problem.
for (LPTSTR pszz = pszzStart; *pszz; pszz += lstrlen(pszz) + 1) {
... do something with pszz ...
}
As assumed in this answer, it seems that the code expects double null terminated arrays of string. Therefore, I wonder how I could check the contents of the inputStr string, in order to check if it actually contains only one null terminator char.
NOTE: the number of characters in the string printed from printf instruction is twice the value returned by the lstrlen(str) function call at the first iteration.
OK, now that you've included the rest of the code it is clear that it is indeed meant to parse a set of consecutive strings. The problem is that you're mixing narrow and wide string types. All you need to do to fix it is change the variable definitions (and remove the casts):
char *arrayStr[STR_COUNT];
char *inputStr;
char *str;
// calls a function from external library
// in order to set the inputStr string
set_input_str(param1, &inputStr, param3);
str = inputStr;
while( *str != '\0' )
{
if( debug )
printf("String[%d]: %s\n", i, str);
arrayStr[i] = str;
str = str + strlen(str) + 1;
i++;
}
Specifically, the issue was occurring on this line:
while( *str != '\0' )
since you hadn't cast str to char * the comparison was looking for a wide nul rather than a narrow nul.
str = str + strlen(str) + 1;
You go out of bounds, change to
str = str + 1;
or simply:
str++;
Of course you are inconsistently using TSTR and strlen, the latter assuming TCHAR = char
In any case, strlen returns the length of the string, which is the number of characters it contains not including the nul character.
Your arithmetic is out by one but you know you have to add one to the length of the string when you allocate the buffer.
Here however you are starting at position 0 and adding the length which means you are at position len which is the length of the string. Now the string runs from offset 0 to offset len - 1 and offset len holds the null character. Offset len + 1 is out of bounds.
Sometimes you might get away with reading it, if there is extra padding, but it is undefined behaviour and here you got a segfault.
This looks to me like code that expects double null terminated arrays of strings. I suspect that you are passing a single null terminated string.
So you are using something like this:
const char* inputStr = "blah";
but the code expects two null terminators. Such as:
const char* inputStr = "blah\0";
or perhaps an input value with multiple strings:
const char* inputStr = "foo\0bar\0";
Note that these final two strings are indeed double null terminated. Although only one null terminator is written explicitly at the end of the string, the compiler adds another one implicitly.
Your question edit throws a new spanner in the works? The cast in
strlen((char*)str)
is massively dubious. If you need to cast then the cast must be wrong. One wonders what LPTSTR expands to for you. Presumably it expands to wchar_t* since you added that cast to make the code compile. And if so, then the cast does no good. You are lying to the compiler (str is not char*) and lying to the compiler never ends well.
The reason for the segmentation fault is already given by Alter's answer. However, I'd like to add that the usual style of parsing a C-style string is more elegant and less verbose
while (char ch = *str++)
{
// other instructions
// ...
}
The scope of ch is only within in the body of the loop.
Aside: Either tag the question as C or C++ but not both, they're different languages.
I can think of 2 ways to convert a string to int: strtol and std::stringstream. The former doesn't report errors (if string is not a representation of a number), the latter throws an exception BUT it is too relaxed. An example:
std::wstring wstr("-123a45");
int result = 0;
try { ss >> result; }
catch (std::exception&)
{
// error handling
}
I want to detect an error here because the whole string is not convertible to int, but no exception is being thrown and result is set to -123.
How can I solve my task using standard C++ facilities?
You erroneously believe that strtol() does not provide error checking, but that is not true. The second parameter to strtol() can be used to detect if the entire string was consumed.
char *endptr;
int result = strtol("-123a45", &endptr, 10);
if (*endptr != '\0') {
/*...input is not a decimal number */
}
There's std::stoi, or std::strtol.
The first throws an exception (and is in C++11 and later), the other you have to manually check (as it's originally a standard C function).
And you can indeed use std::strtol to check that a string is a valid number:
char some_string[] = "...";
char *endptr;
long value = std::strtol(some_string, &endptr, 10);
if (endptr == some_string)
{
// Not a valid number at all
}
else if (*endptr != '\0')
{
// String begins with a valid number, but also contains something else after the number
}
else
{
// String is a number
}
An alternative approach, you could convert to an int, and then convert that back into a wstring, and check the strings for equality.
Not a good idea for doubles, and you would probably need to trim the input string of whitespace even for ints.
I am really confused. I have to be missing something rather simple but nothing I am reading about strtol() is making sense. Can someone spell it out for me in a really basic way, as well as give an example for how I might get something like the following to work?
string input = getUserInput;
int numberinput = strtol(input,?,?);
The first argument is the string. It has to be passed in as a C string, so if you have a std::string use .c_str() first.
The second argument is optional, and specifies a char * to store a pointer to the character after the end of the number. This is useful when converting a string containing several integers, but if you don't need it, just set this argument to NULL.
The third argument is the radix (base) to convert. strtol can do anything from binary (base 2) to base 36. If you want strtol to pick the base automatically based on prefix, pass in 0.
So, the simplest usage would be
long l = strtol(input.c_str(), NULL, 0);
If you know you are getting decimal numbers:
long l = strtol(input.c_str(), NULL, 10);
strtol returns 0 if there are no convertible characters at the start of the string. If you want to check if strtol succeeded, use the middle argument:
const char *s = input.c_str();
char *t;
long l = strtol(s, &t, 10);
if(s == t) {
/* strtol failed */
}
If you're using C++11, use stol instead:
long l = stol(input);
Alternately, you can just use a stringstream, which has the advantage of being able to read many items with ease just like cin:
stringstream ss(input);
long l;
ss >> l;
Suppose you're given a string char const * str. Now convert it like this:
#include <cstdlib>
#include <cerrno>
char * e;
errno = 0;
long n = std::strtol(str, &e, 0);
The last argument 0 determines the number base you want to apply; 0 means "auto-detect". Other sensible values are 8, 10 or 16.
Next you need to inspect the end pointer e. This points to the character after the consumed input. Thus if all input was consumed, it points to the null-terminator.
if (*e != '\0') { /* error, die */ }
It's also possible to allow for partial input consumption using e, but that's the sort of stuff that you'll understand when you actually need it.
Lastly, you should check for errors, which can essentially only be overflow errors if the input doesn't fit into the destination type:
if (errno != 0) { /* error, die */ }
In C++, it might be preferable to use std::stol, though you don't get to pick the number base in this case:
#include <string>
try { long n = std::stol(str); }
catch (std::invalid_argument const & e) { /* error */ }
catch (std::out_of_range const & e) { /* error */ }
Quote from C++ reference:
long int strtol ( const char * str, char ** endptr, int base );
Convert string to long integer
Parses the C string str interpreting its content as an integral number of the specified base, which is returned as a long int value. If endptr is not a null pointer, the function also sets the value of endptr to point to the first character after the number.
So try something like
long l = strtol(pointerToStartOfString, NULL, 0)
I always use simply strol(str,0,0) - it returns long value. 0 for radix (last parameter) means to auto-detect it from input string, so both 0x10 as hex and 10 as decimal could be used in input string.
I want to get int from cstring.
Here is Code.
CStringArray paramArray;
paramArray.Add((LPCSTR)"5");
paramArray.Add((LPCTSTR)"151");
pvarArguments = new CComVariant[2];
pvarArguments[0] = (LPCTSTR)paramArray[1];
CString str;
str = (CStringA)pvarArguments[0];
int nlen = _wtoi(str.GetBuffer());
When I run my program, I always get value 0, and I can't understand why it is.
Please help me.
From TFM (emphasis mine):
Each function returns the int value produced by interpreting the input
characters as a number. The return value is 0 for atoi and _wtoi, if
the input cannot be converted to a value of that type.
Print the string or examine it using a debugger. There may be invalid (including unprintable) characters in the string.
It's hard to tell even what you are trying to do. You do know that C++ arrays are 0-based, right? I ask because this line of code:
pvarArguments[0] = (LPCTSTR)paramArray[1];
is totally messed up. I don't understand why it's not throwing an exception when trying to index an element in a CStringArray that is equal to the count of elements. You can only index to count-1 ==>> which in this case is "0".
Your pvarArguments[0] will have junk in it--I have no idea why an exception wasn't thrown.
If you want to get a different type out of a variant, you can use VariantChangeType() and not mess with wcstoi or atoi. It will give an error code if it fails instead of just returning 0. If you are hell bent on using wcstoi or atoi on a CString, use _tstoi() which works whether you nave UNICODE defined or not.
CStringA implies ANSI string type which would require atoi not _wtoi.
I suggest:
CString str(pvarArguments[0]);
int nlen = atoi(str.GetString());
GetBuffer() is not ideal because you must remember to later ReleaseBuffer().
EDIT: In light of the new information, try this:
paramArray.Add(L"5");
paramArray.Add(L"151");
The L macro makes the string wchar_t aware. If L doesn't work try _T instead. And then use _wtoi or _tstoi.
CStringArray paramArray;
paramArray.Add(_T("5"));
paramArray.Add(_T("151"));
CComVariant *pvarArguments = new CComVariant[2];
pvarArguments[0] = (LPCTSTR)paramArray[1];
CString str;
str = pvarArguments[0].bstrVal;
int nlen = _ttoi(LPCTSTR(str));
per suggestion above, this compiles for me:
rs->GetFieldValueString(0).Left(1) == sBoroCode
&& (_ttoi(LPCTSTR(sLowHouseNo)) % 2) == (_ttoi(LPCTSTR(rs->GetFieldValueString(2))) % 2)
Friends
I want to integrate the following code into the main application code. The junk characters that come populated with the o/p string dumps the application
The following code snipette doesnt work..
void stringCheck(char*);
int main()
{
char some_str[] = "Common Application FE LBS Serverr is down";
stringCheck(some_str);
}
void stringCheck(char * newString)
{
for(int i=0;i<strlen(newString);i++)
{
if ((int)newString[i] >128)
{
TRACE(" JUNK Characters in Application Error message FROM DCE IS = "<<(char)newString[i]<<"++++++"<<(int)newString[i]);
}
}
}
Can someone please show me the better approaches to find junk characters in a string..
Many Thanks
Your char probably is represented signed. Cast it to unsigned char instead to avoid that it becomes a negative integer when casting to int:
if ((unsigned char)newString[i] >128)
Depending on your needs, isprint might do a better job, checking for a printable character, including space:
if (!isprint((unsigned char)newString[i]))
...
Note that you have to cast to unsigned char: input for isprint requires values between 0 and UCHAR_MAX as character values.