String to double conversion allways 0 - c++

I am trying to read a double precision floating point number from a binary file and assign it to a static double variable. I have tried numerous methods however the result of the conversion regardless of the method is 0.The number is correctly read from the file(as an array of characters), however something happens when I try to convert it... The included headers are: # include < string > # include < sstream > #include < stdlib.h >
The code snippet of the method is given bellow:
FILE * pFile;
char mystring [100];
double v;
string temp;
QString t_string;
pFile = fopen ("path_to_binary_file","r");
if (pFile != NULL)
{
if ( fgets (mystring , 100 , pFile) != NULL )
{
//I am putting a \0 on the last position since my array finishes with \n
mystring[strlen(mystring) - 1] = '\0';
temp.assign(mystring, mystring + 12);
t_string = QString::fromStdString(temp);
// std::istringstream s(temp);
// s >> sheethConstant;
v = t_string.toDouble();//atof(mystring);
static_variable = v;
}
fclose (pFile);
}

If the decimal separator is a comma you must handle with locale.
Since you're using Qt is possible to set a QLocale object and setting a locale that uses the comma (I've only take one that works, it's not specific to your situation).
#include <QDebug>
#include <QLocale>
int main(int argc, char *argv[]) {
QString t_string("0,04019173434");
QLocale locale(QLocale::Catalan);
double number = locale.toDouble(t_string);
qDebug() << "String is" << t_string << ", number is " << number;
return 0;
}

Related

Rounding converting from string to double/float

I am trying to extract a number from a string and convert it into a double or float so I can do some numerical operations on it. I am able to isolate the variable I need so the string consists only of the number, but when I try to convert it to a float or double it rounds the value, ie from 160430.6 to 160431.
//Helper Function to Extract Value of Interest
//Based on column of final digit of numbers being same across various FLOPS output files
double findValue(string &line, int &refN){
setprecision(100);
string output;
//go to end column and work backwards to get value string
while(line[refN] != ' '){
output = line[refN] + output;
refN = refN - 1;
}
const char* outputx = output.c_str();
double out = atof(outputx);
//removing the const char* line and replacing atof with stod(output) runs into the same issue
return out;
}
int main()
{
string name;
cin >> name;
ifstream file(name);
//opens file
if(!file.is_open()){"error while opening the file";
}else{
//Temporary Reference Definitions
string ref = "TOGW";
int refN = 25;
string line = findLine(file,ref);
double MTOGW = findValue(line, refN);
cout << MTOGW;
}
return 0;
}
I initially tried using stof() to convert, but that rounded. I have also tried using stod() and stold(), and last tried converting to a const char* and using atof(). I have messed with the setprecision() value, but also have not been able to solve it that way.
I cannot use Boost
You were almost there. The rounding was occurring on output, so that's where you need to use setprecision. That and always use double instead of float to ensure you have enough precision in your variables.
#include <vector>
#include <ranges>
#include <iomanip>
#include <iostream>
#include <string>
using std::string;
double findValue(string &line, int &refN){
//setprecision(100);
string output;
//go to end column and work backwards to get value string
while(line[refN] != ' '){
output = line[refN] + output;
refN = refN - 1;
}
const char* outputx = output.c_str();
double out = strtod(outputx, NULL);
return out;
}
int main()
{
string s = " 160430.6";
int n = s.size() - 1;
std::cout << std::setprecision(10) << findValue(s, n) << '\n';
}
See it in action on the Godbolt compiler.

get turkish chars from string

i wish to write a string in reverse order , i get string with cin and iterating it via for loop from strings length to 0. Problem is when i take turkish char it writes wrongly and also 1 turkish char increases strings length by 2 (i.e. ömür has length 6)
string text = "ömür";
for ( int i = text.length() ; i >= 0; i--)
{
if(!isspace(text[i]) && text[i] != '\0')
{
cout<<text[i];
}
}
expected output = rümö =>
what i get = r??m??
The problem is that nowdays, non ASCII characters take up more than one byte (C++ char). Your best bet is to use a library such as ICU that will sort out the Unicode stuff for you. You could then do:
#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <iostream>
int
main(int argc, char **argv)
{
icu::UnicodeString text("ömür");
text.reverse();
std::cout << text;
}

Increment numbers in char array separated by different delimiters

I have string like this 1-2,4^,14-56
I am expecting output 2-3,5^,15-57
char input[48];
int temp;
char *pch;
pch = strtok(input, "-,^");
while(pch != NULL)
{
char tempch[10];
temp = atoi(pch);
temp++;
itoa(temp, tempch, 10);
memcpy(pch, tempch, strlen(tempch));
pch = strtok(NULL, "-,^");
}
After running through this if I print input it prints only 2 which is first character of the updated string. It does not print all characters in the string. What is the problem with my code?
For plain C, use the library function strtod. Other than atoi, this can update a pointer to the next unparsed character:
long strtol (const char *restrict str, char **restrict endptr, int base);
...
The strtol() function converts the string in str to a long value. [...] If endptr is not NULL, strtol() stores the address of the first invalid character in *endptr.
Since there may be more than one 'not-a-digit' character between the numbers, skip them with the library function isdigit. I placed this at the start of the loop so it would not accidentally convert a string such as -2,3 to -1,4 -- the initial -2 would be picked up first! (And if that is a problem elsewhere, there is also a strtoul.)
Since it appears you want the result in a char string, I use sprintf to copy the output into a buffer, which must be large enough for your possible input plus extra characters caused by a decimal overflow.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
int main (void)
{
char *inputString = "1-2,4^,14-56";
char *next_code_at = inputString;
long result;
char dest[100], *dest_ptr;
printf ("%s\n", inputString);
dest[0] = 0;
dest_ptr = dest;
while (next_code_at && *next_code_at)
{
while (*next_code_at && !(isdigit(*next_code_at)))
{
dest_ptr += sprintf (dest_ptr, "%c", *next_code_at);
next_code_at++;
}
if (*next_code_at)
{
result = strtol (next_code_at, &next_code_at, 10);
if (errno)
{
perror ("strtol failed");
return EXIT_FAILURE;
} else
{
if (result < LONG_MAX)
dest_ptr += sprintf (dest_ptr, "%ld", result+1);
else
{
fprintf (stderr, "number too large!\n");
return EXIT_FAILURE;
}
}
}
}
printf ("%s\n", dest);
return EXIT_SUCCESS;
}
Sample run:
Input: 1-2,4^,14-56
Output: 2-3,5^,15-57
There are two major problems with this code:
First of all,
pch = strtok(input, ",");
When applied to the string 1-2,4^,14-56 will return the token 1-2.
When you call atoi("1-2") you'll get 1, which gets converted to 2.
You can fix this by changing the first strtok to pch = strtok(NULL, "-,^");
Second of all, strtok modifies the string, which means that you lose the original delimiter found. As this looks like a homework exercise, I'll leave you to figure out how to get around this.
I think this could by easier using regular expressions(and C++ instead of C of course):
Complete exmaple:
#include <iostream>
#include <iterator>
#include <regex>
#include <string>
int main()
{
// Your test string.
std::string input("1-2,4^,14-56");
// Regex representing a number.
std::regex number("\\d+");
// Iterators for traversing the test string using the number regex.
auto ri_begin = std::sregex_iterator(input.begin(), input.end(), number);
auto ri_end = std::sregex_iterator();
for (auto i = ri_begin; i != ri_end; ++i)
{
std::smatch match = *i; // Match a number.
int value = std::stoi(match.str()); // Convert that number to integer.
std::string replacement = std::to_string(++value); // Increment 1 and convert to string again.
input.replace(match.position(), match.length(), replacement); // Finally replace.
}
std::cout << input << std::endl;
return 0;
}
Output:
2-3,5^,15-57
strtok modifies the string you pass to it. Either use strchr or something like that to find the delimiters or make a copy of the string to work on.

Parsing command line char arguments as ints with error checking in C++

I'm trying to write a program that takes in two ints as command line arguments. The ints both need to be greater than 0. I understand that I need to convert from char but I have only ever done that using atoi which I now know that I shouldn't do. I've seen people use sstreams and strtol but I'm not sure how those would work in this case. What is the best way to accomplish this?
#include <iostream>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
const int N = 7;
const int M = 8;//N is number of lines, M number of values
//--------------
//-----Main-----
//--------------
int main(int argc, char* argv[])
{
if((argc != 0) && (argv[0] != NULL) && (argv[1] != NULL))
{
N = argv[0];
M = argv[1];
}
else
{
cout << "Invalid or no command line arguments found. Defaulting to N=7 M=8.\n\n" << endl;
}
//Blah blah blah code here
return 0;
}
In C++11 there's stoi, stol, stoll for this: http://en.cppreference.com/w/cpp/string/basic_string/stol
Those throw invalid_argument or out_of_range exceptions if the string isn't in the right format.
There's nothing particularly wrong about using atoi, except it doesn't have a mechanism to report exceptions because it's a C function. So you only have the return value - the problem is all return values of atoi are valid values, so there's no way to differentiate between the return value of 0 as the correct parsing of "0" or the failure of parsing. Also, atoi doesn't do any checks for whether the value is outside the available value range. The first problem is easy to fix by doing the check yourself, the second is more difficult because it involves actually parsing the string - which kind of defeats the point of using an external function in the first place.
You can use istringstream like this:
Pre-C++11:
int val;
std::istringstream iss(arg[i]);
iss >> val;
if (iss.fail()) {
//something went wrong
} else {
//apparently it worked
}
C++11:
int val;
std::istringstream iss(arg[i]);
iss >> val;
if(iss.fail()) {
if(!value) {
//wrong number format
} else if(value == std::numeric_limits<int>::max() ||
value == std::numeric_limits<int>::min()
{
//number too large or too small
}
} else {
//apparently it worked
}
The difference is that pre C++11, only format errors were detected (according to standard), also it wouldn't overwrite the value on error. In C++11, values are overwritten by either 0 if it's a format error or max/min if the number is too large or too small to fit into the type. Both set the fail flag on the stream to indicate errors.
In this specific case, atoi will work fine. The problem with atoi is that you can't differentiate between its returning 0 to signify an error of some sort, and its returning 0 to indicate that the input was 0.
In your case, however, a valid input must be greater than 0. You don't care whether the input was 0 or something else that couldn't be converted. Either way you're doing to set it to the default value.
As such, I'd do something like:
int convert(char *input, int default) {
int x = atoi(input);
return x==0 ? default : x;
}
if (argc > 1)
N = convert(argv[1], 7);
if (argc > 2)
M = convert(argv[2], 8);
Note that argv[0] traditionally holds the name of the program being invoked. Arguments passed on the command line are received as argv[1] through argv[argc-1].
First, you can't use const qualifier for M and N, since you will change their value:
int N = 7;
int M = 8;//N is number of lines, M number of values
Second, you don't need to check for (argv[0] != NULL) && (argv[1] != NULL), just check if argc (argument count) is greater or equal to 3:
if(argc >= 3)
Then you need to convert this into integers. If you don't want to use atoi, and if you don't have C++11 compiler you should use C++'s stringstream or C's strtol
stringstream ss;
int temp;
ss << argv[1]; // Put string into stringstream
ss >> temp; // Get integer from stringstream
// Check for the error:
if(!ss.fail())
{
M = temp;
}
// Repeat
ss.clear(); // Clear the current content!
ss << argv[2]; // Put string into stringstream
ss >> temp; // Get integer from stringstream
// Check for the error:
if(!ss.fail())
{
N = temp;
}
so, whole code will look like this:
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <sstream>
using namespace std;
int N = 7;
int M = 8;//N is number of lines, M number of values
//--------------
//-----Main-----
//--------------
int main(int argc, char* argv[])
{
if(argc >= 3)
{
stringstream ss;
int temp;
ss << argv[1]; // Put char into stringstream
ss >> temp; // Get integer from stringstream
// Check for the error:
if(!ss.fail())
{
M = temp;
}
// Repeat
// empty
ss.clear();
ss << argv[2]; // Put char into stringstream
ss >> temp; // Get integer from stringstream
// Check for the error:
if(!ss.fail())
{
N = temp;
}
cout << M << " " << N;
}
else
{
cout << "Invalid or no command line arguments found. Defaulting to N=7 M=8.\n\n" <<
endl;
}
//Blah blah blah code here
return 0;
}
Also, C header files include with c prefix, not with .h suffix (<cstdio> instead of <stdio.h>)

How to put two backslash in C++

i need to create a function that will accept a directory path. But in order for the compiler to read backslash in i need to create a function that will make a one backslash into 2 backslash.. so far this are my codes:
string stripPath(string path)
{
char newpath[99999];
//char *pathlong;
char temp;
strcpy_s(newpath, path.c_str());
//pathlong = newpath;
int arrlength = sizeof(newpath);
for (int i = 0; i <= arrlength ;i++)
{
if(newpath[i] == '\\')
{
newpath[i] += '\\';
i++;
}
}
path = newpath;
return path;
}
this code receives an input from a user which is a directory path with single backslash.
the problem is it gives a dirty text output;
int arrlength = sizeof(newpath); causes the size of your entire array (in chars) to be assigned to arrlength. This means you are iterating over 99999 characters in the array, even if the path is shorter (which it probably is).
Your loop condition also allows goes one past the bounds of the array (since the last (99999th) element is actually at index 99998, not 99999 -- arrays are zero-based):
for (int i = 0; newpath[i]] != '\0'; i++)
Also, there is no reason to copy the string into a character array first, when you can loop over the string object directly.
In any case, there is no need to escape backslashes from user input. The backslash is a single character like any other; it is only special when embedded in string literals in your code.
In this line:
if(newpath[i] = '\\')
replace = with ==.
In this line:
newpath[i] += '\\';
This is supposed to add a \ into the string (I think that's what you want), but it actually does some funky char math on the current character. So instead of inserting a character, you are corrupting the data.
Try this instead:
#include <iostream>
#include <string>
#include <sstream>
int main(int argc, char ** argv) {
std::string a("hello\\ world");
std::stringstream ss;
for (int i = 0; i < a.length(); ++i) {
if (a[i] == '\\') {
ss << "\\\\";
}
else {
ss << a[i];
}
}
std::cout << ss.str() << std::endl;
return 0;
}
lots wrong. did not test this but it will get you closer
http://www.cplusplus.com/reference/string/string/
string stripPath(string path)
{
string newpath;
for (int i = 0; i <= path.length() ;i++)
{
if(path.at(i) == '\\')
{
newpath.append(path.at(i));
newpath.append(path.at(i));
}
else
newpath.append(path.at(i));
}
return newpath;
}
But in order for the compiler to read
backslash in i need to create a
function that will make a one
backslash into 2 backslash
The compiler only reads string when you compile, and in that case you will need two as the first back slash will be an escape character. So if you were to have a static path string in code you would have to do something like this:
std::string path = "C:\\SomeFolder\\SomeTextFile.txt";
The compiler will never actually call your function only compile it. So writing a function like this so the compiler can read a string is not going to solve your problem.
The condition if (newpath[i] = '\\') should be if (newpath[i] == '\\').
The statement newpath[i] += '\\'; will not give the intended result of concatenation. It will instead add the integral value of '\\' to newpath[i].
Moreover why are you using a char newpath[99999]; array inside the function. newpath could be std::string newpath.
int main()
{
std::string path = "c:\\test\\test2\\test3\\test4";
std::cout << "orignal path: " << path << std::endl;
size_t found = 0, next = 0;
while( (found = path.find('\\', next)) != std::string::npos )
{
path.insert(found, "\\");
next = found+4;
}
std::cout << "path with double slash: " << path << std::endl;
return 0;
}