Konwersja float na const char*

Konwersja float na const char*
M9
  • Rejestracja:ponad 9 lat
  • Ostatnio:10 miesięcy
  • Postów:78
0

W jaki sposób mogę przekonwertować zmienną float na const char* ?
Zrobiłem coś takiego:

Kopiuj
float var = 12.34
(std::to_string(var)).c_str()

i to nawet działa, tylko że w wyniku tej operacji dostaję 21.3400000, a potrzebuję tylko dwie cyfry po przecinku.

edytowany 1x, ostatnio: mlp99
Patryk Miszczak
  • Rejestracja:około 8 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:Poznań
  • Postów:13
1

Możesz spróbować przez stringstream:

Kopiuj
ostringstream ss;
ss << setprecision(3) << f;
const char* str = ss.str().c_str();

Jakoś tak, napisałem z palca, musisz sprawdzić czy działa.

edytowany 1x, ostatnio: Patryk Miszczak
twonek
Zapisywanie wyniku c_str() to niebezpieczna praktyka. Ten wskaźnik może już nie wskazywać na nic sensownego w momencie użycia.
kq
W tym przypadku użycie tego wskaźnika (no, dereferencja) to po prostu UB.
M9
  • Rejestracja:ponad 9 lat
  • Ostatnio:10 miesięcy
  • Postów:78
0

Powyższa metoda niestety nie wyświetla mi żadnego napisu. Spróbowałem jeszcze zrobić tak:

Kopiuj
	const char* val = (std::to_string(data.dx.vol)).c_str();
	char valC[6];

	for (int i = 0; i < 5; i++) {
		valC[0] = *(val + i);
	}

i valC przekazać do funkcji ale niestety też nie działa. Natomiast jeżeli napiszę valC[6] = "12.34" i to przekażę jako parametr do funkcji to się wyświetla. Musi więc być to wina konwersji i prawdopodobnie jak twonek wyżej wspomniał pewnie coś z tym wskaźnikiem jest nie tak.

edytowany 1x, ostatnio: mlp99
twonek
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 2 lata
  • Postów:2500
1
Kopiuj
valC[0] = *(val + i);

skoro do tej samej komórki valC[0] zapisujesz kolejne literki, to jak ma działać?

Ale ta metoda jest ułomna z definicji. c_str() się używa od razu w wywołaniu funkcji, bo tylko wtedy masz gwarancję poprawności danych.

several
  • Rejestracja:prawie 16 lat
  • Ostatnio:około 5 godzin
3

@mlp jeżeli dobrze zrozumiałem, że stringa potrzebujesz przekazać do jakiejś funkcji, i chcesz tylko pierwsze pięć znakó

Kopiuj
void yourFunc(const char *strFloat) { ... }

const auto str  = std::to_string(data.dx.vol).substr(0,5);

yourFunc(str.c_str());

vpiotr
Trzeba tylko jeszcze te "5" wyliczyć...
MarekR22
no i dla wartości 2.5677 25.677 256.77 2567.7 nie dostaniesz oczekiwanego wyniku: 2.57 25.68 256.77 2567.70. Nawet jak policzysz to 5 to i tak zaokrąglanie przepada.
several
Wiem, znam słabości tego jednolinijkowca. Post napisałem na szybko na podstawie prób autora, setpresicion pojawiło się wyżej więc założyłem że autor jest go świadomy.
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
1

Miks pierwszej i ostatniej wersji:

Kopiuj
#include <iostream>
#include <sstream>
#include <iomanip>

using namespace std;

void myFunc(const char *strFloat) {
	cout << "myFunc: ";
	while(*strFloat) {
		cout << *(strFloat++);
	}
	cout << endl;
}

int main() {
  const float var = 12.34;	
  ostringstream ss;
  ss << std::fixed << setprecision(2) << var;
  myFunc(ss.str().c_str());
  return 0;
}

http://ideone.com/ocOgkL

edytowany 1x, ostatnio: vpiotr
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:dzień
  • Lokalizacja:Szczecin
6

Ale kombinujecie.

Kopiuj
char buf[32];
sprintf(buf, "%.2f", 12.34);

ewentualnie

Kopiuj
std::stringstream foo;
foo << std::fixed << std::setprecision(2) << 12.34;
std::string out;
foo >> out;

Jak dla mnie metoda z format stringiem jest tutaj czytelniejsza, strzelałbym też, że szybsza.

A sposób zaprezentowany w innych miejscach, t.j. wywoływanie .c_str() na obiekcie tymczasowym jest szalenie zdradliwy. Czas życia danych wskazywanych przez ten wskaźnik jest równy czasowi życia obiektu tymczasowego, więc nawet jeśli @several i @vpiotr zastosowali go poprawnie, to bardzo bym odradzał jego stosowanie w praktyce. Szczególnie przez mniej doświadczonych programistów.


edytowany 1x, ostatnio: kq
Zobacz pozostały 1 komentarz
kq
Thx, fixed.
vpiotr
Ja tam nie lubię C w C++ (cstdio). Ale ze sprintf na stosowej zmiennej pewnie szybciej.
kq
Też nie lubię, ale różnica czytelności jest w mojej opinii dość wyraźna na korzyść rozwiązania rodem z C.
vpiotr
Można jeszcze dodać, że c_str() wywołane na obiekcie nie-tymczasowym też może być zdradliwe (wartość może się zdezaktualizować po zmianie wartości łańcucha "out").
Azarien
właściwie jedyne co można bezpiecznie zrobić z c_str() to przekazać do funkcji. a i to pod warunkiem, że funkcja nie zapisuje tego wskaźnika na później.
AK
  • Rejestracja:prawie 7 lat
  • Ostatnio:około miesiąc
  • Postów:3561
0
mlp99 napisał(a):

W jaki sposób mogę przekonwertować zmienną float na const char* ?
Zrobiłem coś takiego:

Kopiuj
float var = 12.34
(std::to_string(var)).c_str()

i to nawet działa, tylko że w wyniku tej operacji dostaję 21.3400000, a potrzebuję tylko dwie cyfry po przecinku.

liczba zmiennoprzecinkowa nie ma takiej czy innej ilości cyfr po przecinku. Jest po prostu liczbą, w rzeczywistości binarną. Wypadało by odróżniać liczbę od jej widzialnego formatowania na 'outpucie'.

Co więcej, niektóre liczby nie istnieją (problem reprezentacji).
Przykładowa** float 12.34** też** nie istnieje**. jej "bardziej prawdziwa" wartość to 12.3400002 (może jakaś inna platforma wyliczy przykładowo 12.339997).

Niestety wiedza o zmiennym przecinku kiedyś tak podstawowa, jakoś zanikła wśród mas programistycznych. To czasem może skopać pewną część ciała. Jeszcze o ograniczonej dokładności ktoś by sobie coś przypomniał, o problemie reprezentacji nieliczni. Zarówno biblioteki, a zwłaszcza IDE robią MSZ krzywdę jak prezentują liczby zbyt "przyjaźnie" (a fałszywe)

Użyta w innym miejscu liczba to 21.3400002.

Zgadzam się z kolegami, którzy przestrzegają przed c_str() itd, te fragmenty są pełne UB/ błedów... ale mi to dodatkowo pachnie jakimś problemem XY


Bo C to najlepszy język, każdy uczeń ci to powie
edytowany 4x, ostatnio: AnyKtokolwiek

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.