I usually program in python which has a string to integer converter built in but when i use C++ it doesn't seem to work so I decided to make my own.
this is what i made so far
C++:
int strtoint(string str)
{
int values [str.length()];
int return_value = 0;
for (int i=0; i < str.length(); ++i)
if(str.at(str.length()-1-i) == '1')
values[i] = 1;
else if(str.at(str.length()-1-i) == '2')
values[i] = 2;
else if(str.at(str.length()-1-i) == '3')
values[i] = 3;
else if(str.at(str.length()-1-i) == '4')
values[i] = 4;
else if(str.at(str.length()-1-i) == '5')
values[i] = 5;
else if(str.at(str.length()-1-i) == '6')
values[i] = 6;
else if(str.at(str.length()-1-i) == '7')
values[i] = 7;
else if(str.at(str.length()-1-i) == '8')
values[i] = 8;
else if(str.at(str.length()-1-i) == '9')
values[i] = 9;
for (int i=0; i < str.length(); ++i)
return_value += values[i]^(10*i);
return return_value;
}
I seem to get very weird answers like "12" returns 13 and "23" returns 11.
I know about stoi but I prefer to make my own so I can learn C++.
Three problems I can see on a quick look.
The first is that
int values [str.length()];
is not valid C++. It is using a feature from the 1999 C standard, which some C++ compilers support as an extension, but it is still not valid C++.
The second is lack of handling of 0s or errors (non-digit characters) in input.
The third is the statement
return_value += values[i]^(10*i);
^ is a bitwise XOR operator in C++. Not mathematical exponentiation.
A couple of other minor tips.
You can probably simplify your code a lot by using iterators.
Also, with all standard character sets, the roman digits are sequential, starting with '0'. So a simple way to convert a digit to the numeric value you want is digit - '0', which will convert '0' to 0, '1' to 1, .... '9' to 9.
In C++ I use std::stringstream to convert std::string to int. Simple example I found:
#include <sstream>
#include <iostream> //used for cout
int main()
{
std::string str = "12345";
std::istringstream ss(str);
int i;
ss >> i;
if (ss.fail())
{
// Error
}
else
{
std::cout << "The integer value is: " << i;
}
return 0;
}
Mistakes in your code you can find in #Peter answer.
You could simplify this a lot with the char conversion where you just subtract the value of '0' and the use of iterators, especially reverse iterators which make it simpler to calculate the value.
#include <cmath>
#include <string>
/*! Converts a char to an integer.
* #param c the character to convert
* #return the integer value [0-9] or -1 if not convertible
*/
int chartoint(const char c)
{
auto value = (c - '0');
if (value < 0 || value > 9)
{
value = -1;
}
return value;
}
/*! Converts a string to an integer.
* #param string the string to convert
* #return the converted integer value or 0 if not convertible
*/
int strtoint(const std::string& string)
{
auto integer = 0;
const auto begin = string.rbegin();
for (auto it = begin, end = string.rend(); it != end; ++it)
{
const auto current = chartoint(*it);
if (current == -1)
{
integer = 0;
break;
}
else
{
const auto factor = static_cast<int>(std::pow(10, (it - begin)));
integer += factor * current;
}
}
return integer;
}
Test run:
#include <cassert>
int _tmain(int argc, _TCHAR* argv[])
{
assert(strtoint("1") == 1);
assert(strtoint("1x") == 0);
assert(strtoint("12") == 12);
assert(strtoint("10") == 10);
return 0;
}
Related
Trying to figure how I can use isDigit to ignore every character except x, X, e, E within a string. As you can see below I'm doing duodecimal to decimal with x equal to 10 and e equal to 11 (not case sensitive). Having trouble with cin.ignore(). The output should be 36. The string duo should read in the 3 then 0 and negate the rest.
#include <cmath>
#include <iomanip>
#include <iostream>
#include <limits>
#include <string>
using namespace std;
main() {
using str_t = std::string::size_type;
str_t idx = 0;
int decValue = 0;
string duo = "30-something";
while (isspace(duo.at(idx)) && idx < duo.length()) {
idx++;
}
for (std::string::size_type i = 0; i < duo.length(); ++i) {
decValue *= 12;
if (isdigit(duo.at(i))) {
decValue += duo.at(i) - '0';
}
else if (duo.at(i) == 'x' || duo.at(i) == 'X') {
decValue += 10;
}
else if (duo.at(i) == 'e' || duo.at(i) == 'E') {
decValue += 11;
}
/// Program works if this executable line is taken out
else if (!char.isDigit(duo.at(i))) {
cin.ignore();
}
}
cout << decValue << endl;
}
Below I modified your code so that it gives correct answer. For input 30-something it gives 36 as output.
As I understood you want to finish conversion right after 30 i.e. ignore -something. For such behaviour I put a flag stop_on_first_non_digit in my code, if it is true then it finishes on first non-digit character. But you may set it to false then I just skip non-digit chars but use all chars that are digits, for example -something has e in it, so contains one digit, if stop_on_first_non_digit is false then this single e digit will be used. By default now it is true so that it behaves the way you like.
Also I kept your logic of skipping first spaces in a string so you can input 30-something (leading spaces) and it gives 36 too.
Try it online!
#include <string>
#include <cctype>
#include <iostream>
int main() {
std::string duo = "30-something";
bool stop_on_first_non_digit = true;
size_t i = 0;
int decValue = 0;
while (i < duo.length() && std::isspace(duo.at(i)))
++i;
for (; i < duo.length(); ++i) {
char c = duo.at(i);
int digit = 0;
if (std::isdigit(c))
digit = c - '0';
else if (c == 'x' || c == 'X')
digit = 10;
else if (c == 'e' || c == 'E')
digit = 11;
else {
if (stop_on_first_non_digit)
break;
else
continue;
}
decValue *= 12;
decValue += digit;
}
std::cout << decValue << std::endl;
}
Output:
36
Our teacher gave us this exercise:
"Given a string like '-5,14' write a function that returns the float value of -5,14
I used double here just to test the precision, but it also didn't work with floats.
[also i'm from Europe, we use the comma instead of the dot. Oh also we aren't allowed to use the type string and bool, we have to "make" them like in C]
This is what i came up with, and it seems to work a little bit. Positive numbers are similar, but wrong, and given a negative number, the result is similar to 10 times the positive of the given number.
It should work like this:
I read the string into an array of characters;
I check if the first character is a minus. if so, subtract 1 from the number of integer figures because i will count them later starting from index 0;
I count the number of integer figures with a loop from the start of the array to the ',' character;
I count the number of decimal figures with a loop from after the ',' to the end of the string;
[Keep in mind for the next step that, following the ASCII table, the code for the character of a number is that number + 48]
I add to the result variable every integer figure multiplied by ten to the power of whatever place in the number it has.
I do the same for the deicmal values but with the negative exponent.
if the number was negative, i multiply the result with -1.
But for some reason it's not working properly. The lower the number is, the less accurate it is (given 4,5 the result is 9, but given 345,543 the result is 350,43)
#include <iostream>
#define EOS '\0'
#define DIM 100
#define TRUE 1
#define FALSE 0
void leggiN(char* c)
{
std::cout << "Insert a number: ";
std::cin >> c;
}
double stof(char* str)
{
double Result = 0;
double ascii_to_int = 48;
int i = 0;
int j = 0;
int IntegerDigits = 0;
int DecimalDigits = 0;
int CommaIndex;
int isNegative = FALSE;
if (str[0] == '-')
{
IntegerDigits = -1;
isNegative = TRUE;
}
while (str[i] != ',')
{
++IntegerDigits;
++i;
}
CommaIndex = i;
++i;
while (str[i] != EOS)
{
++DecimalDigits;
++i;
}
for (i = (CommaIndex - 1); i >= 0; --i)
{
Result += (str[i] - ascii_to_int) * (std::pow(10, j));
++j;
}
j = 0;
for (i = (CommaIndex + 1); str[i] != EOS; ++i)
{
Result += (str[i] - ascii_to_int) * (std::pow(10, -j));
++j;
}
if (isNegative == 1)
Result = Result * -1;
return Result;
}
int main()
{
char str[DIM];
leggiN(str);
std::cout << stof(str);
}
use j = 1 to start your second for loop. You are trying to raise 10 to the power of -0
j = 1;
for (i = (CommaIndex + 1); str[i] != EOS; ++i)
{
Result += (str[i] - ascii_to_int) * (std::pow(10, -j));
++j;
}
If your code return 9.0 when you enter "4,5", your problem has nothing to do with imprecision.
There are other problems in your code, I've tried to un it and got a SEGFAULT...
#include <iostream>
#define EOS '\0' // 0 being such a special value, there is no need to
// define a named constant for it.
#define DIM 100
#define TRUE 1 // the language defines boolean values, avoid defining
#define FALSE 0 // unnecessary named constants for something that already
// exists.
void leggiN(char* c)
{
std::cout << "Insert a number: ";
std::cin >> c; // Inserting from cin to a char* is a BIG no-no.
// some compilers won't even allow it, for good reasons
// i.e.: what is the length of the array pointed to?
}
double stof(char* str) // you are indicating that you may modify str?
{
double Result = 0;
double ascii_to_int = 48; // this is a terrible name.
int i = 0;
int j = 0;
int IntegerDigits = 0;
int DecimalDigits = 0;
int CommaIndex;
int isNegative = FALSE;
if (str[0] == '-') // is str a valid pointer? what happens if NULL ??
{
IntegerDigits = -1;
isNegative = TRUE;
// you fail to skip the sing character, should have ++i here.
}
while (str[i] != ',') // what happens if there is no ',' in the string?
{ // you should check for str[i] == 0.
++IntegerDigits;
++i;
}
CommaIndex = i;
++i;
while (str[i] != EOS)
{
++DecimalDigits; // why do you count decimal digits?
++i; // you do not use this result anyway...
}
for (i = (CommaIndex - 1); i >= 0; --i)
{
// what happens if you have non-digit characters? they participate
// in the conversion??
// you call std::pow(), but do not include <cmath> at the top of the file.
// isn't str[i] - '0' clearer ?
Result += (str[i] - ascii_to_int) * (std::pow(10, j));
++j;
}
j = 0;
for (i = (CommaIndex + 1); str[i] != EOS; ++i)
{
Result += (str[i] - ascii_to_int) * (std::pow(10, -j));
++j;
}
if (isNegative == 1) // you had defined constants fot this, but don't use them.
Result = Result * -1;
return Result;
}
int main()
{
char str[DIM];
leggiN(str);
std::cout << stof(str);
}
Here is one way to achieve what you want.
#include <iostream>
#include <string>
const char DECIMAL_POINT = ','; // we'll use a named constant here....
// usually, we'd have to check the locale
// for regional specific information.
// works like atod(), conversion stops at end of string of first illegal character.
double stof(const char* str) {
// check input, must be not null, not empty
if (!str || str[0] == 0)
return 0;
int i = 0;
bool isNegative = false;
// take care of leading sign
if (str[0] == '-' || str[0] == '+') {
isNegative = (str[0] == '-');
++i;
}
// convert integer part.
double result = 0;
while ('0' <= str[i] && str[i] <= '9') {
result = (result * 10) + (str[i] - '0');
++i;
}
// only do decimals if they are there.
if (str[i] != DECIMAL_POINT)
return (isNegative) ? -result : result;
++i; // skip decimal point
double decimals = 0;
double multiplier = .1;
while ('0' <= str[i] && str[i] <= '9') {
decimals += (str[i] - '0') * multiplier;
++i;
multiplier *= .1;
}
result += decimals;
return (isNegative) ? -result : result;
}
int main() {
// always use std::string to read strings from cin.
std::string str;
std::cout << "Insert a number: ";
std::cin >> str;
std::cout << "in: " << str << " out: " << stof(str.c_str()) << '\n';
return 0;
}
I've almost solved this exercise:
Binary to Decimal and Back Converter - "Develop a converter to convert a decimal number to binary or a binary number to its decimal equivalent."
So, the binary to decimal converter works perfectly, but the other one doesn't. convertToBinary() function returns crap and I don't know why. Here is the code:
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
char* convertToBinary(int dec);
int convertToDec(const char* bin);
int main()
{
std::cout << convertToBinary(100) << std::endl; // wtf!
return 0;
}
char* convertToBinary(int dec)
{
char binary[15] = "";
int result;
for(int i = 0; dec >= 1; dec /= 2, ++i)
{
result = !((dec % 2) == 0);
binary[i] = result + 48;
}
for(int i = strlen(binary); strlen(binary) % 4 != 0; ++i) // add some zeros to make it look cool
binary[i] = '0';
for(int i = 0, j = strlen(binary)-1; i < j; ++i, --j) // reverse the array
{
char temp = binary[i];
binary[i] = binary[j];
binary[j] = temp;
}
std::cout << binary << std::endl; // looking good!
return binary;
}
int convertToDec(const char* bin)
{
int dec = 0;
int size = strlen(bin);
for(int i = 0; *bin; ++i, ++bin)
{
int ch = *bin - 48;
dec += ch * pow(2, size - i - 1);
}
return dec;
}
Using c language
char *convertToBinary(int value)
{
char *binary;
size_t length;
size_t i;
length = 8 * sizeof(value);
binary = malloc(1 + length);
if (binary == NULL)
return NULL;
for (i = 0 ; i < length ; ++i)
binary[length - i - 1] = (value & (1 << i)) ? '1' : '0';
binary[length] = '\0';
return binary;
}
int binaryToDecimal(const char *binary)
{
int value;
size_t length;
size_t i;
value = 0;
length = strlen(binary);
for (i = 0 ; i < length ; i++)
value |= (binary[i] == '1') ? (1 << (length - i - 1)) : 0;
return value;
}
Using c++ language
std::string convertToBinary(int value)
{
std::string binary;
size_t length;
length = 8 * sizeof(value);
binary.resize(length);
for (size_t i = 0 ; i < length ; ++i)
binary[length - i - 1] = (value & (1 << i)) ? '1' : '0';
return binary;
}
int binaryToDecimal(const std::string &binary)
{
int value;
size_t length;
value = 0;
length = binary.length();
for (size_t i = 0 ; i < length ; i++)
value |= (binary[i] == '1') ? (1 << (length - i - 1)) : 0;
return value;
}
to convert from binary to decimal, you can use strtol of course.
Your mistake is returning a local variable, a local variable is automatically deallocated when the function returns, and hence the garbage you got.
When you do something like this:
char *toString(...)
{
char res[MAX_RES];
// fill res
return res;
}
you create the array res as a local array on the stack. This array goes out of scope when you return from the function; a pointer to this array is no longer valid and most likely will point to garbage.
If you want to use C-style char buffers, there are two ways to get around this:
Allocate the result on the heap.
char *toString(...)
{
char *res = malloc(MAX_RES);
// fill res
return res;
}
Data allocated on the heap with malloc will be valid until explicitly released with free. The advantage of this approach is that you can make the string as long as you wish. Thedrawback is that the allocation might fail. It is also worth noting that the caller now owns the string and is responsible for freeing it:
char *x = toString(...);
// do stuff with x
free(x);
**Pass the buffer and maximum length **
int toString(char *res, size_t max, ...)
{
// fill res
}
That is the approach many library functions use, notably snprintf. The caller has to provide their own buffer and information on the maximum allowable length in order to avoid buffer overflows. This approach must keep track of the buffer size and truncate the result if necessary, possibly maintaining the string null-terminated. Such functions could be void, but it is customary to return the actual string length or -1 as error indicator.
It is called like this:
char x[200];
toString(x, sizeof(x), ...);
// do stuff with x
I'm trying to verify ISBN numbers in C but when I run the program I get the following error: Disallowed system call: SYS_socketcall
This is for a homework assignment in a CS class. I've done all the work so it's not like I'm asking people to do my assignment for me. I'm just wondering why I'm getting this error as I'm new to the C language; I come from a Java background as well as some web programming languages. Anyways, here's the assignment description if it'll help:
Perform a check on the characters in an ISBN to verify correctness.
The check character is computed as follows:
First, compute the sum of the first digit plus two times the second digit
plus three times the third digit, ... , plus nine times the ninth digit. The
last character is the remainder when the sum is divided by 11. If the
remainder is 10, the last character is X. For example, the sum for
the ISBN 0-8065-0959-7 is
1*0 + 2*8 + 3*0 + 4*6 + 5*5 + 6*0 + 7*9 + 8*5 + 9*9 = 249
The remainder when 249 is divided by 11 is 7, the last character in the ISBN.
The check character is used to validate an ISBN.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int checkISBN( char[] );
#define size 18L
int main() {
int i,j;
char* s[size] = {
"0-8065-0959-7",
"0-534-37964-8",
"0-618-50298-X",
"0-8065-0959-8",
"0-534-37964-9",
"0-618-50298-5",
"0-534-37964-8",
"0-618-50298-X",
"032121353X",
"0321199553",
"0201794896",
"0870495275",
"0452264464",
"0536901562",
"158901104X",
"080801076X",
"80-902734-1-6"
"158901104X" };
for( i = 0; i < size; i++){
if( checkISBN( s[i] ) == 1 )
printf("%-15s is a valid ISBN \n",s[i]);
else
printf("%-15s is NOT a valid ISBN*****\n",s[i]);
}
putchar('\n'); //write a newline
system("pause");`enter code here`
return EXIT_SUCCESS;
}
int checkISBN( char s[] )
{
int result = 0;
int i;
int n = 1;
int sum = 0;
char ch[10];
int final[10];
int sizeOfArray = strlen(s);
for(i=0; i<sizeOfArray; i++){
if(s[i] == '-'){
++i;}
if(s[strlen(s)-1] == 'X'){
s[strlen(s)-1] = 10;}
ch[i] = s[i];
}
for(i=0; i<10; i++){
final[i] = atoi(&ch[i]);}
for(i=0; i<9; i++){
sum+= final[i]*n;
++n;}
int checkCharacter = sum%11;
if(checkCharacter == final[9]){
result = 1;}
return result;}
#include <ctype.h>
int checkISBN( char s[] ) {
int i, n = 1, sum = 0, checksum;
for(i=0; s[i]; ++i){
if(s[i] == '-')
continue;
if(n<10 && isdigit(s[i]))
sum += n++*(s[i] - '0');
else if(n==10){
if(s[i] == 'X')
checksum = 10;
else if(isdigit(s[i]))
checksum = s[i] - '0';
}
}
return sum % 11 == checksum;
}
also
"80-902734-1-6", //need comma
Given a string of characters, how can I go through it and assign all the numbers within that string into an integer variable, leaving out all other characters?
I want to do this task when there is a string of characters already read in through gets(), not when the input is read.
unsigned int get_num(const char* s) {
unsigned int value = 0;
for (; *s; ++s) {
if (isdigit(*s)) {
value *= 10;
value += (*s - '0');
}
}
return value;
}
Edit: Here is a safer version of the function.
It returns 0 if s is NULL or cannot be converted to a numeric value at all. It return UINT_MAX if the string represents a value larger than UINT_MAX.
#include <limits.h>
unsigned int safe_get_num(const char* s) {
unsigned int limit = UINT_MAX / 10;
unsigned int value = 0;
if (!s) {
return 0;
}
for (; *s; ++s) {
if (value < limit) {
if (isdigit(*s)) {
value *= 10;
value += (*s - '0');
}
}
else {
return UINT_MAX;
}
}
return value;
}
This is a simple C++ way to do that:
#include <iostream>
#include <sstream>
using namespace std;
int main(int argc, char* argv[]) {
istringstream is("string with 123 embedded 10 12 13 ints", istringstream::in);
int a;
while (1) {
is >> a;
while ( !is.eof() && (is.bad() || is.fail()) ) {
is.clear();
is.ignore(1);
is >> a;
}
if (is.eof()) {
break;
}
cout << "Extracted int: " << a << endl;
}
}
Look up the strtol function from the standard C library. It allows you to find the part of a character array that is a number, and points to the first character that isn't a number and stopped the parsing.
You can use sscanf: it works like scanf but on a string (char array).
sscanf might be overkill for what you want though, so you can also do this:
int getNum(char s[])
{
int ret = 0;
for ( int i = 0; s[i]; ++i )
if ( s[i] >= '0' && s[i] <= '9' )
ret = ret * 10 + (s[i] - '0');
return ret;
}