Using .c_str' with pointers (and also pointers to pointers) - c++

so, I encountered a little problem and I am kinda stuck.
Basically I am trying to pass the value of a string** in C-type form to a char* string
The code is as follows:
static int BuildDBListSql( std::string **SqlBuf,
const char* ColumnNames,
const char* TableNames,
const char* CmdText,
sUINT Mode)
{
int rtnval = sSUCCESS;
const char * testSql = ( Mode & 02 ) ? ColumnNames : CmdText;
if ( SU_DbControl::DbCreateTradeTempTables(testSql) != sSUCCESS )
{
sLogMessage("Problem with temporary table results", sLOG_ERROR, 0);
return( sERROR );
}
if ( Mode & 02 )
{
*SqlBuf = new std::string[strlen(ColumnNames) + SQL_MAX_SELECT*40];
*SqlBuf = &std::string(ColumnNames);
if ( !( Mode & 010 ) )
{
// Attach State/Retrieval SQL.
char* SqlBufcopy = (*SqlBuf)->c_str();
sSQLInsertStateAndRetrieval( sDbConvertMode( Mode ), SqlBufcopy);
}
}
// SQL fragments are being passed:
else
{
size_t sqlBufLength = 0;
if ( Mode & 010 )
{
sqlBufLength = strlen(ColumnNames) + strlen(TableNames) + strlen(CmdText) + SQL_MAX_SELECT;
*SqlBuf = new std::string[ sqlBufLength ];
//sprintf( *SqlBuf, "SELECT %s FROM %s %s ",
*SqlBuf = fmt::format("SELECT {} FROM {} {} ", ColumnNames, TableNames, CmdText); // ColumnNames, TableNames, CmdText );
}
else
{
std::string *sqlPtr = new char[strlen(CmdText) + 2*SQL_MAX_SELECT];
strcpy( sqlPtr, CmdText );
sSQLSpecializeWhereClause( TableNames, sqlPtr );
sqlBufLength = strlen(ColumnNames) + strlen(TableNames) + SQL_MAX_SELECT;
sqlBufLength += strchr(TableNames, ',') ? strlen(CmdText) : strlen(sqlPtr);
*SqlBuf = new char[ sqlBufLength ];
sprintf( *SqlBuf, "SELECT %s From %s %s",
ColumnNames,
TableNames,
strchr( TableNames, ',' ) ? CmdText : sqlPtr );
delete [] sqlPtr;
// Attach State/Retrieval SQL
rtnval = sSQLInsertStateAndRetrieval( sDbConvertMode( Mode ),
*SqlBuf );
}
}
if (Mode & 0100)
{
char * tempBuf = sEntitySQLToDbSQL(*SqlBuf);
if( tempBuf )
{
delete [] *SqlBuf;
*SqlBuf = new char[ strlen(tempBuf) + 1];
strcpy(*SqlBuf, tempBuf);
}
else
{
sLogMessage("Error in sEntitySQLToDbSQL", sLOG_ERROR, 0);
return( sERROR );
}
}
return rtnval;
}
i get this error when running the solution: related to this line of code char* SqlBufcopy = (*SqlBuf)->c_str();
left of '.c_str' must have class/struct/union, type is std::string**
I kinda understand that the error is there due to me trying to get a c-type string out of a pointer, but I dont know the correct syntax to do what i want to do.
I tried with
char *SqlBufcopy = *SqlBuf.c_str()
also with
char *SqlBufcopy = *SqlBuf->c_str()
and it didnt work, help pls

To fix the error you ask about, change char *SqlBufcopy = *SqlBuf.c_str(); to
char *SqlBufcopy = (*SqlBuf)->c_str();
Reason: SqlBuf is pointer to pointer (which makes no sense at all), so to get to the actual object, you need to dereference it twice.

Related

How to manage memory while reading CSV using Apache Arrow C++ API?

I don't understand memory management in C++ Arrow API. I use Arrow 1.0.0 and I'm reading CSV file. After a few runs of ReadArrowTableFromCSV, my memory is full of allocated data. Am I missing something? How can I free that memory? I don't see any method in memory pool to clear all allocated memory. Code Listing below.
void LoadCSVData::ReadArrowTableFromCSV( const std::string & filePath )
{
auto tableReader = CreateTableReader( filePath );
ReadArrowTableUsingReader( *tableReader );
}
std::shared_ptr<arrow::csv::TableReader> LoadCSVData::CreateTableReader( const std::string & filePath )
{
arrow::MemoryPool* pool = arrow::default_memory_pool();
auto tableReader = arrow::csv::TableReader::Make( pool, OpenCSVFile( filePath ),
*PrepareReadOptions(), *PrepareParseOptions(), *PrepareConvertOptions() );
if ( !tableReader.ok() )
{
throw BadParametersException( std::string( "CSV file reader error: " ) + tableReader.status().ToString() );
}
return *tableReader;
}
void LoadCSVData::ReadArrowTableUsingReader( arrow::csv::TableReader & reader )
{
auto table = reader.Read();
if ( !table.ok() )
{
throw BadParametersException( std::string( "CSV file reader error: " ) + table.status().ToString() );
}
this->mArrowTable = *table;
}
std::unique_ptr<arrow::csv::ParseOptions> LoadCSVData::PrepareParseOptions()
{
auto parseOptions = std::make_unique<arrow::csv::ParseOptions>( arrow::csv::ParseOptions::Defaults() );
parseOptions->delimiter = mDelimiter;
return parseOptions;
}
std::unique_ptr<arrow::csv::ReadOptions> LoadCSVData::PrepareReadOptions()
{
auto readOptions = std::make_unique<arrow::csv::ReadOptions>( arrow::csv::ReadOptions::Defaults() );
readOptions->skip_rows = mNumberOfHeaderRows;
readOptions->block_size = 1 << 27; // 128 MB
readOptions->column_names.reserve( mTable->GetNumberOfColumns() );
for ( auto & colName : mTable->GetColumnsOrder() )
{
readOptions->column_names.emplace_back( colName );
}
return readOptions;
}
std::unique_ptr<arrow::csv::ConvertOptions> LoadCSVData::PrepareConvertOptions() const
{
auto convertOptions = std::make_unique<arrow::csv::ConvertOptions>( arrow::csv::ConvertOptions::Defaults() );
for ( auto & col : mTable->GetColumsInfo() )
{
convertOptions->column_types[col.second.GetName()] = MyTypeToArrowDataType( col.second.GetType() );
}
convertOptions->strings_can_be_null = true;
return convertOptions;
}
std::shared_ptr<arrow::io::ReadableFile> LoadCSVData::OpenCSVFile( const std::string & filePath )
{
MTR_SCOPE_FUNC();
auto inputFileResult = arrow::io::ReadableFile::Open( filePath );
if ( !inputFileResult.ok() )
{
throw BadParametersException( std::string( "CSV file reader error: " ) + inputFileResult.status().ToString() );
}
return *inputFileResult;
}
Maciej, the method TableReader::Read should return shared_ptr<arrow::Table>. The arrow::Table itself has a number of shared pointers to structures which eventually contain the data. To free up the data you will need to make sure that the arrow::Table and any copies of it are destroyed. This should happen as soon as that shared_ptr goes out of scope. However, it appears you are storing the table in a member variable here (which is to be expected, you probably want to use the data after you read it):
this->mArrowTable = *table;
So now you have a second copy of the arrow::Table instance. You could reassign this->mArrowTable to a new blank table or you could destroy whatever this is. Of course, if you are making any other copies of the table then you will need to ensure those go out of scope as well.

What wrong I have done? The function of GetDiskFreeSpaceExA didn't work at all

I tried to use GetDiskFreeSpaceExA function, but it doesn't work:
int drvNbr = PathGetDriveNumber(db7zfolderw);
if (drvNbr == -1) // fn returns -1 on error
{
const char * errmsg = "error occured during get drive number";
strcpy_s(retmsg, strlen(errmsg) + 1, errmsg);
return -3;
}
char driverletter = (char)(65 + drvNbr);
string driverstr(1, driverletter);
driverstr = driverstr + ":";
PULARGE_INTEGER freespace = 0;
PULARGE_INTEGER totalnumbtype = 0;
PULARGE_INTEGER totalnumberfreebyte = 0;
fileSize = SzArEx_GetFileSize(&db, i);
BOOL myresult=GetDiskFreeSpaceExA(
driverstr.c_str(),
freespace,
totalnumbtype,
totalnumberfreebyte
);
The value of variable freespace is 0. I have no idea why it didn't work if the value of variable which is driverstr.c_str() was D:?
Thanks for your help.
You need to supply pointers to variables that will hold the value returned. Right now you a re supplying null pointers so nothing is retured:
::ULARGE_INTEGER freespace{};
::ULARGE_INTEGER totalnumbtype{};
::ULARGE_INTEGER totalnumberfreebyte{};
::BOOL myresult
{
::GetDiskFreeSpaceExA
(
driverstr.c_str()
, &freespace
, &totalnumbtype
, &totalnumberfreebyte
)
};
It would also be a good idea to use wide char versions of these functions.

Difficulty implementing code 128 C rule

Code related to text encoding:
const char* toCode128C( const char* texto ) {
int tamanhoTexto = strlen( texto );
int tamanhoComando = strlen( "{C" ) + tamanhoTexto;
char* printerCodBarras = new char[ tamanhoComando ];
memcpy( printerCodBarras, "{C", tamanhoComando );
for ( int i = 0; i < tamanhoTexto; i += 2 ) {
int num = QString( texto ).mid( i, 2 ).toInt();
QString vl = QString( static_cast<char>( num ) );
strncat( printerCodBarras, vl.toStdString().c_str(), 1 );
}
return printerCodBarras;
}
Encoding occurs successfully, except when it contains a "00" for example code 59900001, the transformation occurs from two characters to two characters, or error occurs when encoding the value "00", thus making the (00) is not printed.

Weird error on mysql_stmt_execute

I have a weird error when trying to execute mysql_stmt_execute.
The flow goes:
I get the list of the tables in my database I am connecting. (catalog, schema and name)
For every table I'm getting the list of foreign keys, fields and indexes.
Everything goes good until I hit the table named performance_schema.events_stages_summary_by_account_by_event_name.
I get the error: Identifier name "events_stages_summary_by_account_by_event_name" is too long. The weird thing is that the name is not an identifier - it is a parameter to the query and it is less than 64 characters which is the identifier limit.
Below is the relevant code:
std::wstring query3 = L"SELECT kcu.column_name, kcu.ordinal_position, kcu.referenced_table_schema, kcu.referenced_table_name, kcu.referenced_column_name, rc.update_rule, rc.delete_rule FROM information_schema.key_column_usage kcu, information_schema.referential_constraints rc WHERE kcu.constraint_name = rc.constraint_name AND kcu.table_catalog = ? AND kcu.table_schema = ? AND kcu.table_name = ?;";
char *catalog_name = row[0] ? row[0] : NULL;
char *schema_name = row[1] ? row[1] : NULL;
char *table_name = row[2] ? row[2] : NULL;
MYSQL_BIND params[3];
unsigned long str_length1, str_length2, str_length3;
str_length1 = strlen( catalog_name ) * 2;
str_length2 = strlen( schema_name ) * 2;
str_length3 = strlen( table_name ) * 2;
str_data1 = new char[str_length1], str_data2 = new char[str_length2], str_data3 = new char[str_length3];
memset( str_data1, '\0', str_length1 );
memset( str_data2, '\0', str_length2 );
memset( str_data3, '\0', str_length3 );
memset( params, 0, sizeof( params ) );
strncpy( str_data1, catalog_name, str_length1 );
strncpy( str_data2, schema_name, str_length2 );
strncpy( str_data3, table_name, str_length3 );
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char *) str_data1;
params[0].buffer_length = strlen( str_data1 );
params[0].is_null = 0;
params[0].length = &str_length1;
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char *) str_data2;
params[1].buffer_length = strlen( str_data2 );
params[1].is_null = 0;
params[1].length = &str_length2;
params[2].buffer_type = MYSQL_TYPE_STRING;
params[2].buffer = (char *) str_data3;
params[2].buffer_length = strlen( str_data3 );
params[2].is_null = 0;
params[2].length = &str_length3;
if( mysql_stmt_bind_param( res1, params ) )
{
std::wstring err = m_pimpl->m_myconv.from_bytes( mysql_stmt_error( res1 ) );
errorMsg.push_back( err );
result = 1;
break;
}
else
{
prepare_meta_result = mysql_stmt_result_metadata( res1 );
if( !prepare_meta_result )
{
std::wstring err = m_pimpl->m_myconv.from_bytes( mysql_stmt_error( res1 ) );
errorMsg.push_back( err );
result = 1;
break;
}
else
{
if( mysql_stmt_execute( res1 ) )
{
std::wstring err = m_pimpl->m_myconv.from_bytes( mysql_stmt_error( res1 ) );
errorMsg.push_back( err );
result = 1;
break;
}
Could someone please shed some light on the error? I can probably try to skip this table but I'd prefer not to.
[EDIT]
mysql --version
mysql ver 14.14 Distrib 5.6.35, for Linux (x86+64) using Editine wrapper
[/EDIT]
Edit:
Seems that the code is indeed OK and the strncpy is OK. I mistakenly read that the allocation was twice the length of the string but the length was still only one length of the string.
The reason why you see that error is because you are using a string which is not null terminated. This is caused by the fact that strncpy does not null-terminate the string if it exceeds the given limit and the limit you use is the actual length of the string:
memset( str_data1, '\0', str_length1 );
strncpy( str_data1, catalog_name, str_length1 );
params[0].buffer_length = strlen( str_data1 );
A better way to do this would be to use either snprintf(3) that does null terminate the string or by using the std::string constructor that takes a const char* and a length as parameters.

How do I cast a void pointer to a int[3]?

I need to call a 3rd party library and pass in an int[3] as a void * like this [works]:
int pattern[3] = {2,4,10};
if ( OSTaskCreate( BlinkLED,
( void * ) pattern,
( void * ) &BlinkTaskStack[USER_TASK_STK_SIZE],
( void * ) BlinkTaskStack,
MAIN_PRIO - 1 ) != OS_NO_ERR )
{
iprintf( "*** Error creating blink task\r\n" );
}
But now I need to parse a string to get the pattern array and I can't seem to get it right.
First I pass the string into the parser and get back the array:
int (&ParseBlinkOnCommand(char rxbuffer[3]))[3]
{
// Code parses rxbuffer and creates the 3 ints needed
int pattern[3] = {repeats, onTicks, offTicks};
return pattern;
}
Then I try to pass it to the OSTaskCreate just like I did before:
int pattern2[3] = ParseBlinkOnCommand(rxbuffer);
if ( OSTaskCreate( BlinkLED,
( void * ) pattern2,
( void * ) &BlinkTaskStack[USER_TASK_STK_SIZE],
( void * ) BlinkTaskStack,
MAIN_PRIO - 1 ) != OS_NO_ERR )
{
iprintf( "*** Error creating remote blink task\r\n" );
}
but I get the error 'array must be initialized with a brace-enclosed initializer'.
What is the right way to do this?
First, ParseBlinkOnCommand returns reference to local object and so return dangling reference.
Second C-array are not copyable, so int pattern2[3] = ParseBlinkOnCommand(rxbuffer); should be int (&pattern2)[3] = ParseBlinkOnCommand(rxbuffer);.
but why not using std::vector or std::array (or custom structure) ?
std::vector<int> ParseBlinkOnCommand(const char (&rxbuffer)[3])
{
// Code parses rxbuffer and creates the 3 ints needed
return {repeats, onTicks, offTicks};
}
And then
auto pattern2 = ParseBlinkOnCommand(rxbuffer);
if ( OSTaskCreate( BlinkLED,
pattern2.data(),
&BlinkTaskStack[USER_TASK_STK_SIZE],
BlinkTaskStack,
MAIN_PRIO - 1 ) != OS_NO_ERR )
{
iprintf( "*** Error creating remote blink task\r\n" );
}