Ahoj, potřebuju převést const unsigned char * proměnnou na string, ale nic co jsem zkoušel nefunguje. Buď se to ani nezkompiluje a pokud náhodou ano, tak to hodí Segmentation fault (core dumped). :(
Díky moc za jakoukoliv radu.
Fórum › C / C++
(C++) Převod const unsigned char * na string
Aha, tak problém nebude v převodu, ale v něčem jiném (pole?). Tady je kód, aby jste pochopil/i, o co se snažím.
if(rc == SQLITE_DONE || rc == SQLITE_ROW) {
while(rc == SQLITE_ROW) {
int rowCount = 0;
int columnCount = sqlite3_column_count(statement);
for(int i = 0; i < columnCount; i++){
string returnData[rowCount] = {(const char*)(sqlite3_column_text(statement, i))};
cout << returnData[rowCount][columnCount] << "\n";
}
rc = sqlite3_step(statement);
rowCount++;
}
cout << "yes" << "\n";
} else {
cout << "no" << "\n";
}
string returnData[rowCount] // tohle je pole stringů,
= {(const char*)(sqlite3_column_text(statement, i))}; // ve kterém inicializuješ první string hodnotou sloupce
cout <<
returnData[rowCount] // tímhle získáš string z pole
// teda vlastně ne, když je ten index mimo rozsah toho pole
[columnCount] // a tímhle znak z toho stringu
// teda kdyby to byl platný index v platném stringu.
<< "\n";
Věci, které jsi dělal už stokrát! Nečaruj, přemýšlej.
for (int i = 0; i < columnCount; i++) {
cout << sqlite3_column_text(statement, i) << "\n";
}
Souhlas s gna. Kazdopadne jako zacatecnik bys mel psat jeste komentare "co si myslis, ze by to melo delat", protoze z toho kodu je to pomerne hodne nepochopitelne.
Jako jo, evidentne se tam snazis vypsat jednotlive sloupce. Ale opravdu silenym zpusobem a bez pochopeni, jak vlastne funguji pole, natoz dvourozmerne.
Ták, problém vyřešen. Ano, komentáře bych psát měl, na toto jsem hodně líný. Jestli je i nějaký elegantnější způsob, sem s ním, rád se přiučím. :) Co se týče dvourozměrných polí, tak o ty jsem "štřejchnul" v PHP. Nějak moc jsem je nepotřeboval, takže jsem je asi úplně nepochopil. V C++ jsem nový. Učím se ho metodou pokus, omyl cca. 5 měsíců a ještě k tomu na praktickém příkladu, takže jsem dá se říci přeskočil teorii a něco mi asi uteklo.
No, každopádně tady je funkční kód, který dělá přesně to co chci:
if(rc == SQLITE_DONE || rc == SQLITE_ROW) {
while(rc == SQLITE_ROW) {
int rowCount = 1;
int columnCount = sqlite3_column_count(statement);
string returnData[rowCount][columnCount];
for(int i = 0; i < columnCount; i++) {
returnData[rowCount-1][i] = (const char*)(sqlite3_column_text(statement, i));
cout << returnData[rowCount-1][i] << "\n";
}
cout << "\n";
rc = sqlite3_step(statement);
rowCount++;
}
cout << "yes" << "\n";
} else {
cout << "no" << "\n";
}
Každopádně díky moc. :)
Nu moc sis nepomohl, jakmile ti to vrati vic jak jeden radek, tak ses zase mimo pole :D Nicmene nastesti si tu inkrementovanou hodnotu nepamatujes, takze ses stale na prvnim radku.
Projdeme si tvoje reseni:
while(rc == SQLITE_ROW) {
// pocet radek nastavis na 1 (v kazdem kole)
int rowCount = 1;
// pocet sloupcu si alespon zjistis:
int columnCount = sqlite3_column_count(statement);
// zahadne definujes dvourozmerne pole o jednom radku a sloupce jsou spravne
string returnData[rowCount][columnCount];
// jedine co tu dava jakz takz smysl:
for(int i = 0; i < columnCount; i++) {
// pro prvni radek dejme tomu funguje (ostatne ted je kazda iterace while prvni radek :D),
// ale proc je to potreba ukladat do pole, kdyz jen vypisujes aktualni polozku?
returnData[rowCount-1][i] = (const char*)(sqlite3_column_text(statement, i));
// proc radeji nepouzijes reseni co tu nahodil gna?
// Tady na toto neni potreba ani extra promenna, operator<< umi vypsat i const char*
cout << returnData[rowCount-1][i] << "\n";
}
cout << "\n";
rc = sqlite3_step(statement);
// A toto by zpusobilo pad. Tedy kdyby sis pamatoval v dalsim kole inkrementovanou hodnotu.
// Nastesti platnost teto promenne hned pote skonci a zacinas s cistym stitem znovu od 1:
rowCount++;
}
A ted trosku vylepsene (podle gna):
while(rc == SQLITE_ROW) {
// toto je jedina promenna co se hodi, zjisteni jeji hodnoty
// muze byt narocne, tudiz je lepsi mit to mimo podminku cyklu
int columnCount = sqlite3_column_count(statement);
for(int i = 0; i < columnCount; i++) {
// rovnou to hodim do coutu, jelikoz to stejne nikde nepouzivas
// a cout zvlada vypsat i C retezce
cout << sqlite3_column_text(statement, i) << "\n";
}
cout << "\n";
rc = sqlite3_step(statement);
}
#7 KIIV
Pardon, já zapomněl dodat jeden důležitý fakt, a to ten, že si tu returnData proměnnou chci vrátit zpět do funkce, ze které ji volám (referencí). Teď si to vypisuji jen "pro oko", abych viděl jestli ta proměná něco vrací. :)
#8 richard.zavodny
tak to tim spise musis udelat poradne (ted z toho nevymlatis nic jineho nez posledni radek). A hlavne budes muset pouzit spis neco jako vector (kterej se alespon zkopiruje, pokud ho vratis z funkce). Urcite nemuzes vratit ukazatel na to pole, jelikoz s koncem existence funkce prestane existovat i to pole.
#8 richard.zavodny
v Delphi jsem tohle řešil přes vlastní typ T2DArrayString = array of array of string; předáván jako 'var' argument funkci, ve funkci pak lze změnit oba rozměry pole pomocí length pro řádky (lze postupně přidávat každou řádkou z DB zvětšit length o 1) a poté pro sloupce, dokonce mám dojem, že šlo pro každou řádku nastavit jiný počet sloupců.
V C++ moc nedělám, ale vypadalo by to asi takto:
//ve volající funkci definovat pole:
string **Data;
// **Data předávat v argumentu funkce
// nastavení počtu řádků - již ve funkci
Data = new string*[rowCount]; // rowCount z DB - první rozměr = počet řádek před smyčkou řádek,
// v případě přidávání po jedné by bylo třeba udělat reSize funkci,
// kde vytvoříš nové větší pole a původní do něj zkopíruješ,
// poté původní smažeš a přiřadíš mu referenci nového.
int Radek = 0; // čítač řádek
// Smyčka procházení řádků
{
// Před smyčkou sloupců definuješ pomocné pole
string *Radka = new string[columnCount];
// FOR smyčka na sloupce pak
{
Radka[i] = (const char*)(sqlite3_column_text(statement, i));
}
Data[Radek] = Radka; // pole sloupců do druhého rozměru pole Data
Delete [] Radka;
Radek++;
}
inspiraci jsem čerpal zde http://stackoverflow.com/questions/16001803/pointer-to-pointer-dynamic-two-dimensional-array
#10 MilanL
Ten delete [] Radka; tam nedava smysl. Radka je alokovane pole a timto ho zlikvidujes a v Data[Radek] mas neplatny pointer.
Daleko lepsi je pouzit vector<vector<string>>. Nebude se resit alokace a dealokace, presuny to zvlada taky samo.
#11 KIIV
no psal jsem, že v C++ toho moc nedělám, pokud mi string *Radka=new string[columnCount]; alokuje vždy novej pointer tak tam samozřejmě delete být nemusí, vlastně ted mi došlo že v těch polích jsou Ukazatele (reference) a ne data. a že ta řádka Data[Radek]=Radka neznamená zkopírování dat z pole do pole, ale předání ukazatele Radka do pole ukazatelů v Data.
Ten Vector mi připadá hodně podobný tomu mému řešení, navíc to je lépe obalený typ než to pole ukazatelů.
Mě celkem jde zpětná analýza jen u některých typů jazyků (C++, OOP PHP a pod) mě matou některé ty tečkové, <<, >> , :: a typové konvence.
#10 MilanL
Díky za opdověď, bohužel z tvého "kódu" nechápu absolutně nic, zkrátka je v tom chaos.
#9 KIIV
Pole bych si měl umět vrátit, když jsem schopný vrátit si proměnnou, nebo se mýlím? Já si ve volající funkci definuji proměnnou, pošlu ji v parametru funkce a potom ji pomocí reference vrátím (nastavím novou hodnotu) a dále jsem schopný s ní pracovat, i když funkce již "zanikne".
Mám databázovou funkci:
void db(string *data, string databaseName, char *databaseStatement) {
sqlite3 *db;
sqlite3_stmt *statement;
int rc;
rc = sqlite3_open(databaseName.c_str(), &db);
rc = sqlite3_prepare_v2(db, databaseStatement, -1, &statement, 0);
rc = sqlite3_step(statement);
if(rc == SQLITE_DONE || rc == SQLITE_ROW) {
int rowCount = 1;
while(rc == SQLITE_ROW) {
int columnCount = sqlite3_column_count(statement);
string returnData[rowCount][columnCount];
for(int i = 0; i < columnCount; i++) {
returnData[rowCount-1][i] = (const char*)(sqlite3_column_text(statement, i));
cout << returnData[rowCount-1][i] << "\n";
}
rc = sqlite3_step(statement);
rowCount++;
}
cout << "yes" << "\n";
} else {
cout << "no" << "\n";
}
sqlite3_finalize(statement);
sqlite3_close(db);
}
A toto je hlavní funkce:
int main() {
string dataReturn;
db(&dataReturn, "test.db", "SELECT * FROM test");
return 0;
}
V prvním parametru předávám prázdnou proměnnou data, v té chci později vrátit pole s daty z databáze. Takhle mám postavené všechny funkce, které něco vrací a chtěl bych se toho pokud možno držet. :)
#14 richard.zavodny
ma to jen nekolik hacku:
string dataReturn;
Je JEDEN kontejnerovy objekt typu string. Zduraznuji ten jeden. Muzes do toho nacpat prave jeden retezec.
A zase dokola az do zblbnuti:
int rowCount = 1; // aspon je to uz mimo while
while(rc == SQLITE_ROW) {
int columnCount = sqlite3_column_count(statement);
// TOTO JE LOKALNI PROMENNA!!!!! Jakmile skonci jeji platnost (na konci kazdeho kola while!),
// tak se neda spolehnout na ty data! Natoz je nekam vracet z funkce
string returnData[rowCount][columnCount];
for(int i = 0; i < columnCount; i++) {
returnData[rowCount-1][i] = (const char*)(sqlite3_column_text(statement, i));
cout << returnData[rowCount-1][i] << "\n";
}
rc = sqlite3_step(statement);
rowCount++;
}
Par pveci, co o predavani parametru v C/C++ evidentne netusis:
- jednoduche datove typy (vcetne pointeru) a objekty se vzdy predavaji hodnotou.
- Muzes zmenit kam ukazuje pointer, ktery sis predal do funkce, ale venku je to stale ten puvodni.
- Zmenit muzes jen data, na ktere se odkazuje. - Pole je vlastne jen pointer s informaci o poctu polozek.
- Pole se NIKDY NEPREDAVA HODNOTOU, vzdy jen tim POINTEREM, tudiz ve funkci uz neznas rozmer.
- Pokud chces referenci, musis pouzit referenci a jeste pridat i spravny rozmer pole (pripadne pouzit template, kde se z toho da i rozmer rovnou vytahnout). Nicmene u statickeho pole stejne NEZMENIS JEHO UMISTENI!!!!
#14 richard.zavodny
to co řešíš je v podstatě dataset, osobně bych si na ty data nadefinoval třídu, potřebuješ z funkce vrátit 2 rozměrné pole včetně rozměrů (řádky X sloupce)
Nejsou náhodou v ROW=0 názvy sloupců?
#15 KIIV
zajímala by mě jedna věc, jak by se u 2D vectoru přidávali postupně ty řádky, sloupce bych věděl vector[I].push..., ale ten 1. rozměr mi není jasnej vector.push_back(vector<string>) ?
Zajímalo by mě i jak by to vypadalo s předáním toho 2d vektoru do funkce. Něco jsem zkoušel a nešlo mi to. Přes 2h jsem si s tím hrál s pomocí strýčka Googla a nic.
#16 MilanL
Neco takoveho:
#include <iostream>
#include <string>
#include <vector>
using Row = std::vector<std::string>;
using Rows = std::vector<Row>;
Rows neco_dopln() {
Rows vysledek;
while (vysledek.size() < 6) {
Row radek;
for (int i = 0; i < 6; ++i) {
// ja sqlite nemam, takze jen neco doplnim:
radek.emplace_back(std::to_string((vysledek.size()+1)*1000 + i));
//// v jeho pripade to bude:
// radek.emplace_back(sqlite3_column_text(statement, i));
}
vysledek.emplace_back(std::move(radek)); // konkretne tady se chceme vyhnout kopii
}
return vysledek;
}
int main() {
Rows radky = neco_dopln();
// a vypis
for (Row const & radek : radky) {
std::cout << "| ";
for (std::string const& polozka : radek) {
std::cout << polozka << " | ";
}
std::cout << "\n";
}
}
Vyhoda je, ze to muze mit libovolne dlouhe radky a vzdy jde zjistit, velikost radku i pocet radku. A hlavne se nemusi starat o uvolnovani pameti (pokud pamet alokuje)
Jo ten vypis se da i trosku zjednodusit (pomoci ostream_iterator z headeru <iterator>):
for (Row const & radek : radky) {
std::cout << "| ";
std::copy(radek.begin(), radek.end(), std::ostream_iterator<std::string>(std::cout, " | "));
std::cout << "\n";
}
Da se to udelat i pro Rows. Jen se musi udelat pretizeni operatoru << pro vypis Row.
#17 KIIV
dík, vypadá to s těma vektorama o dost jednodušeji, a je z toho vidět jak se ten první rozměr vytváří tím vkládáním druhého.
Můj fungující testík:
// ConsoleApplication1.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <vector>
#include <iostream>
#include <string>
using namespace std;
vector<vector<string> > Napln()
{
vector<vector<string> > data;
srand(10);
int rCount = 2 + rand() % 8;
int cCount;
for (int i = 0; i < rCount; i++)
{
vector<string> radka;
cCount = 5 + rand() % 5;
for (int j = 0; j < cCount; j++)
{
radka.emplace_back(to_string(1+rand()%9));
}
data.emplace_back(radka);
}
return data;
}
int main()
{
vector<vector<string> > rData = Napln();
for (int i = 0; i < rData.size(); i++)
{
for (int j = 0; j < rData[i].size(); j++)
{
cout << rData[i][j] << "\t";
}
cout << endl;
}
string vstup;
cin >> vstup;
return 0;
}
Přidej příspěvek
Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku
×Vložení zdrojáku
×Vložení obrázku
×Vložení videa
Uživatelé prohlížející si toto vlákno
Podobná vlákna
Převedení system::string na const char — založil majklendek
System::string převést na const char * — založil Martin
Převod Int do Byte (unsigned char) — založil paashi
Const char v C — založil Halancik
Definice const char *[] — založil Remder
Moderátoři diskuze