How does this C++ code work? - c++

enum STR2INT_ERROR { SUCCESS, OVERFLOW, UNDERFLOW, INCONVERTIBLE };
STR2INT_ERROR str2int (int &i, char const *s, int base = 0)
{
char *end;
long l;
errno = 0;
l = strtol(s, &end, base);
if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) {
return OVERFLOW;
}
if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) {
return UNDERFLOW;
}
if (*s == '\0' || *end != '\0') {
return INCONVERTIBLE;
}
i = l;
return SUCCESS;
}
I'm trying to write a program that can parse strings read in from a file into integer values. While looking for a method to do this I found this piece of code above on a stackoverflow post:
How to parse a string to an int in C++?
However, I can't understand how it works.
Specifically, why is the programmer checking if errno == ERANGE if errno is assigned to 0? (is ERANGE a special value? )
secondly, what does "char const *s" - in the arguments list- mean?
PS: I'm not very experienced when it comes to C++ programming.

The code is using strtol() to do the parsing. This is a standard C library function. You can find documentation on strtol() here amongst other places:
strtol() man page on die.net
The errno variable is a special global variable defined by the standard C library. If a function encounters an error it is set to an error code. So while errno is assigned zero at the start of the routine, the strtol() function will assign a new value to errno if it encounters an error. The following if-statements are checking for the overflow and underflow error conditions.
The char const *s parameter is the string to be parsed. Its a pointer to a constant (read-only) string of characters. By convention strings are terminated by a NULL byte.

Whenever I have done string to int conversions in C++ I used the atoi method. There should be plenty of examples online that suit what you want to do

Most of the specialness here is with errno, not the values being compared to.
errno is a global that's used by some (especially older) library functions to signal errors. You assign 0 to it (which implicitly means there's no problem). Then, if it runs into a problem, a library function can assign some non-zero value to it to tell you want went wrong.
After calling the library function, you then typically check 1) whether it's now non-zero, and 2) if so, what value it has. Based on the value that's been assigned, you can react to the type of error that arose.
I should add, however, that many uses of errno are mostly non-portable. The C standard says that errno exists, that no library function assigns 0 to errno, but not a lot more more than that. It does not specify what non-zero values any particular function may assign to it (well, it specifies some non-zero values that some functions assign, but doesn't limit assignments to those values or those functions).

First of all, this is clearly a C program in C++ disguise.
strtol is a function from standard C library, which does the actual work. Its doumentation may be accessed there: http://linux.die.net/man/3/strtol
All other things are just preliminaries and checks.
errno is a special global variable from the C library which may be modified by standard functions in order to set an appropriate error code (yes, it's C legacy and this is not thread-safe). Its value may be set to values defined in standard header "errno.h".

errno is a library-provided global variable that strtol (as well as other library functions) uses to indicate error conditions. In the above code strtol could change errno after the user set it to 0. ERANGE is indeed a named constant provided by the standard library, which stands for some special value used by strtol to indicate out-of-range errors.
Your char const *s question is too vague. What specifically do you not understand in it? The const part means that the user code inside str2int will not be allowed to modify the string pointed by s. The compiler will do its best to prevent any modifying (or potentially modifying) operations on string pointed by s.

Related

C++ Server Program Print While Loop

I am creating a server/client socket program and am in the process of making a method to print server input.
Here's my code:
void *admin_handler (void *ptr) {
char strBuf [100000];
const char strExit [20] = "Server: terminated.";
while(1) {
scanf ("%s", strBuf);
int i;
for (i=0; i < nClient; i++){
if (strBuf == "Exit"){
write (nFDList [i], strExit, strlen (strExit) + 1);
}
else {
write (nFDList [i], strBuf, strlen (strBuf) + 1);
}
}
};
}
When I execute, though, even when I type in "Exit", it still executes the else statement. How can I modify the if statement to execute when I type "Exit"?
The best way to compare strings in C is using strcmp() (or strncmp() if one is interested in safety with unknown strings).
The equality operator == compares the operands directly, after they "decay" to pointers; the pointers do not change and are of course different. strcmp(), by contrast, inspects the contents of the memory pointed to, which may be equal.
As an aside, the same issue exists in Java: == checks whether both sides are the same objects, similar to the C equivalent, while .equals() inspects the object contents, similar to strcmp().
C#, by contrast, overloaded == for strings so that it would indeed look at the contents, which makes a lot of sense for a language where operator overloading is possible (which C is not): Testing the identity of the objects is almost never desired and, as we see, is a common source of error.

sprintf_s() fails with "debug assertion failed" error

The problem is probably something simple, but I couldn't get it to work after hours of research and editing, so here I post my issue.
I am trying to make a function which receives either a single digit integer or a two digit integer and returns it as a string after converting it to a two integer format (e.g. 7 to 07).
char *to_two_digits(int num) {
char num_str[4];
sprintf(num_str, "%d", num);
int length = sizeof(*num_str) / sizeof(char);
static char *return_string;
if (length == 1) {
sprintf_s(return_string, "0%d", num);
return return_string;
}
else if (length == 2) {
*return_string = *num_str;
return return_string;
}
else {
printf("Error! Number cannot be represented as a two-digit.");
exit(1);
}
}
The function fails when the sprintf_s() function is run, with an error that says:
--------------------------- Microsoft Visual C++ Runtime Library-----------
Debug Assertion Failed!
File: minkernel\crts\ucrt\src\appcrt\stdio\output.cpp
Line: 261
Expression: format != nullptr
What is the problem, and how can I fix it? Thank you in advance.
You are passing a null pointer to the sprintf_s function. The pointer that you declare in this line
static char *return_string;
was never initialized to point to anything. Since it is declared static, it is pre-initialized to zero (rather than just having an indeterminate value).
This is what the message is telling you. There is an assert in the sprintf_s code that checks that you have not passed a null pointer, and that is what is firing.
You are supposed to pass in a pointer to a buffer that the function can write into. But since you are using C++, you're really just supposed to use a std::string for this, which you could then return from the function without needing a static variable.
It's exactly what it says — you're passing a null pointer to sprintf_s.
It's that return_string, which you did not initialise to point to anything, let alone a buffer of sufficient size for the actual result. Rather than being of indeterminate value, it is assuredly a null pointer by virtue of being static, but this assurance doesn't help you.
It's actually not a good idea to use static for memory management like this, because your function is 100% non-re-entrant. Usually you'd have your users pass in a buffer of sufficient size for the result, and let that calling scope handle the buffer's lifetime.

Converting strings to ints or doubles

I know this is a repeated question, and I a have looked at a lot of answers for it but none have really been able to help me so far.
I need to be able to pass various strings into two methods one returns a double and the other a int.
The main problem is that I need strict error checking on both methods so that if I pass a string that dose not contain a number and only a number the method does not make a conversion. As I said I've seen a few solutions but the only good one I've seen (that was able to follow) was using Boost which I do not want to use. As for the answer I was not able to follow here is a part of it copied from
How to parse a string to an int in C++?
The best solution
Fortunately, somebody has already solved all of the above problems. The C standard library contains strtol and family which have none of these problems.
enum STR2INT_ERROR { SUCCESS, OVERFLOW, UNDERFLOW, INCONVERTIBLE };
STR2INT_ERROR str2int (int &i, char const *s, int base = 0)
{
char *end;
long l;
errno = 0;
l = strtol(s, &end, base);
if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) {
return OVERFLOW;
}
if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) {
return UNDERFLOW;
}
if (*s == '\0' || *end != '\0') {
return INCONVERTIBLE;
}
i = l;
return SUCCESS;
}
If anyone can explain it a little more I think it is the answer Im looking for I just cant get enough of a grasp of what its doing so that i can apply the idea to my code.
Using strtol (and strtod for doubles) sounds like the right approach. The implementation that you quoted flows straight from the documentation for strtol:
It sets errno to zero before the call (strtol does not change errno on success)
It examines errno upon return of strtol to see if an error has been signaled
The final condition checks that the input is not empty, and that the entire input has been consumed by strtol.
An implementation for doubles would look the same, except you'd use strtod.
As a learning exercise, you might want to try to write this on your own. I suggest starting with some examples. You might want to start by getting a firm grasp on how numbers are represented in writing. What does "42" mean? In other words, what does the 2 represent and what does the 4 represent? Similarly, what does "1000000" mean? Once you get a grasp on these concepts, write down the steps (in English) you would take to convert a string into an integer. From there, start converting it into code. If you get stuck anywhere along the way, feel free to come back with more questions.
I re-worded this question in another location and finally got the answer I was looking for. For any wondering here is the link:
Basics of strtol?

Is std::stoi actually safe to use?

I had a lovely conversation with someone about the downfalls of std::stoi. To put it bluntly, it uses std::strtol internally, and throws if that reports an error. According to them, though, std::strtol shouldn't report an error for an input of "abcxyz", causing stoi not to throw std::invalid_argument.
First of all, here are two programs tested on GCC about the behaviours of these cases:
strtol
stoi
Both of them show success on "123" and failure on "abc".
I looked in the standard to pull more info:
§ 21.5
Throws: invalid_argument if strtol, strtoul, strtoll, or strtoull reports that
no conversion could be performed. Throws out_of_range if the converted value is
outside the range of representable values for the return type.
That sums up the behaviour of relying on strtol. Now what about strtol? I found this in the C11 draft:
§7.22.1.4
If the subject sequence is empty or does not have the expected form, no
conversion is performed; the value of nptr is stored in the object
pointed to by endptr, provided that endptr is not a null pointer.
Given the situation of passing in "abc", the C standard dictates that nptr, which points to the beginning of the string, would be stored in endptr, the pointer passed in. This seems consistent with the test. Also, 0 should be returned, as stated by this:
§7.22.1.4
If no conversion could be performed, zero is returned.
The previous reference said that no conversion would be performed, so it must return 0. These conditions now comply with the C++11 standard for stoi throwing std::invalid_argument.
The result of this matters to me because I don't want to go around recommending stoi as a better alternative to other methods of string to int conversion, or using it myself as if it worked the way you'd expect, if it doesn't catch text as an invalid conversion.
So after all of this, did I go wrong somewhere? It seems to me that I have good proof of this exception being thrown. Is my proof valid, or is std::stoi not guaranteed to throw that exception when given "abc"?
Does std::stoi throw an error on the input "abcxyz"?
Yes.
I think your confusion may come from the fact that strtol never reports an error except on overflow. It can report that no conversion was performed, but this is never referred to as an error condition in the C standard.
strtol is defined similarly by all three C standards, and I will spare you the boring details, but it basically defines a "subject sequence" that is a substring of the input string corresponding to the actual number. The following four conditions are equivalent:
the subject sequence has the expected form (in plain English: it is a number)
the subject sequence is non-empty
a conversion has occurred
*endptr != nptr (this only makes sense when endptr is non-null)
When there is an overflow, the conversion is still said to have occurred.
Now, it is quite clear that because "abcxyz" does not contain a number, the subject sequence of the string "abcxyz" must be empty, so that no conversion can be performed. The following C90/C99/C11 program will confirm it experimentally:
#include <stdio.h>
#include <stdlib.h>
int main() {
char *nptr = "abcxyz", *endptr[1];
strtol(nptr, endptr, 0);
if (*endptr == nptr)
printf("No conversion could be performed.\n");
return 0;
}
This implies that any conformant implementation of std::stoi must throw invalid_argument when given the input "abcxyz" without an optional base argument.
Does this mean that std::stoi has satisfactory error checking?
No. The person you were talking to is correct when she says that std::stoi is more lenient than performing the full check errno == 0 && end != start && *end=='\0' after std::strtol, because std::stoi silently strips away all characters starting from the first non-numeric character in the string.
In fact off the top of my head the only language whose native conversion behaves somewhat like std::stoi is Javascript, and even then you have to force base 10 with parseInt(n, 10) to avoid the special case of hexadecimal numbers:
input | std::atoi std::stoi Javascript full check
===========+=============================================================
hello | 0 error error(NaN) error
0xygen | 0 0 error(NaN) error
0x42 | 0 0 66 error
42x0 | 42 42 42 error
42 | 42 42 42 42
-----------+-------------------------------------------------------------
languages | Perl, Ruby, Javascript Javascript C#, Java,
| PHP, C... (base 10) Python...
Note: there are also differences among languages in the handling of whitespace and redundant + signs.
Ok, so I want full error checking, what should I use?
I'm not aware of any built-in function that does this, but boost::lexical_cast<int> will do what you want. It is particularly strict since it even rejects surrounding whitespace, unlike Python's int() function. Note that invalid characters and overflows result in the same exception, boost::bad_lexical_cast.
#include <boost/lexical_cast.hpp>
int main() {
std::string s = "42";
try {
int n = boost::lexical_cast<int>(s);
std::cout << "n = " << n << std::endl;
} catch (boost::bad_lexical_cast) {
std::cout << "conversion failed" << std::endl;
}
}

Why can I assign/compare int and char in C

I have the code like this :
#include <stdio.h>
main()
{
int c;
c = getchar();
while (c != EOF) {
putchar(c);
c = getchar();
}
}
The C documentation says that the getchar() returns the int value. And in the above program we have assigned c type as an int. And most importantly EOF is a integer constant defined in the header function.
Now if the code changes to something like this:
#include <stdio.h>
main()
{
char c;
c = getchar();
while (c != EOF) {
putchar(c);
c = getchar();
}
}
This code also works! Wait a min, as per C documentation getchar() returnsint, but see in the above code I'm storing it in char. And C compiler doesn't throw any error. And also in while loop I have compared c which is an char with EOF which is an int and compiler doesn't throw any error and my program executes!
Why does the compiler doesn't throw any error in the above two cases?
Thanks in advance.
No. It simply means that the returned value which is an int, implicitly converts into char type. That is all.
The compiler may generate warning messages for such conversion, as sizeof(int) is greater than sizeof(char). For example, if you compile your code with -Wconversion option with GCC, it gives these warning messages:
c.c:5:7: warning: conversion to 'char' from 'int' may alter its value
c.c:8:8: warning: conversion to 'char' from 'int' may alter its value
That means, you should use int to avoid such warning messages.
I'm afraid that the term "dynamic programming language" is too vaguely defined to make a such a fine distinction in this case.
Though I'd argue that implicit converting to one numeric type to another is not a dynamic language feature, but just syntax sugar.
No. Lets look at wikipedia's definition
These behaviors could include extension of the program, by adding new
code, by extending objects and definitions, or by modifying the type
system, all during program execution. These behaviors can be emulated
in nearly any language of sufficient complexity, but dynamic languages
provide direct tools to make use of them.
What you have demonstrated is that a char and int in C/C++ are pretty much the same, and C/C++ automatically casts between the two. Nothing more. There's no modification of the type system here.
Lets rewrite your code to illustrate what's going on
int main(int argc, char** argv)
{
char c;
c = EOF; /* supposing getchar() returns eof */
return (c == EOF) ? 0 : 1;
}
What should the return value of this program be? EOF is not a char, but you cast it to a char. When you do a comparison, that cast happens again, and it gets squashed to the same value. Another way of rewriting this to make it clear what's going on is:
#include <stdio.h>
main()
{
int c;
c = getchar();
while ((char)c != (char)EOF) {
putchar((char)c);
c = getchar();
}
}
EOF is getting squashed; it doesn't matter how it's getting squashed, it could be squashed to the letter 'M', but since it gets squashed the same way every time, you still see it as EOF.
C will let you do what you want, but you have to accept the consequences. If you want to assign an int to a char then you can. Doesn't make it a dynamic language.
(As an aside, the title of this question should be something like "why does c let me assign an int to a char?" and just contain the final paragraph. But presumably that wouldn't attract enough attention. If it had attracted any upvotes then I'd edit the title, but since it isn't I'll leave it as an example of how not to ask a question.)
If you are not reading 7-bit ASCII data, it is possible that \xFF is valid data. If EOF is \xFFFFFFFF and you return the value of getchar() to a char then you can not distinguish EOF from \xFF as data.