Reputation: 25
I'm working with the MySQL C API and trying to execute a prepared statement to delete a row.
-(void) deleteOne:(int) num
{
[self initAndConnectSql];
char copy[30] = "call delete";
strncat(copy, _name, 15);
strncat(copy, "(?)", 4);
MYSQL_STMT * prepared = mysql_stmt_init(&_mysql);
mysql_stmt_prepare(prepared, copy, strlen(copy));
MYSQL_BIND bind[1];
bind[0].buffer_type = MYSQL_TYPE_LONG;
bind[0].buffer = #
bind[0].is_null=0;
bind[0].length= 0;
if (mysql_stmt_bind_param(prepared, bind))
{
printf("error in binding params");
exit(1);
}
if (mysql_stmt_execute(prepared))
{
printf("Error executing prepared statement");
exit(1);
}
mysql_stmt_close(prepared);
mysql_close(&_mysql);
}
This code works fine. But previously when I didn't set the prepared variable as a pointer, I got a pointer being freed was not allocated set a breakpoint in malloc_error_break to debug error. The line was MYSQL_STMT prepared = *mysql_stmt_init(&_mysql);
.
My question is why does setting prepared as a pointer, versus passing in &prepared where it is needed, work? Shouldn't a pointer and an & be equivalent since a pointer stores the address of what it is pointing at and & returns the address, so to a function, they are the same?
Upvotes: 1
Views: 138
Reputation: 7161
From the MySQL API:
23.8.11.15 mysql_stmt_init()
----------------------------
MYSQL_STMT *mysql_stmt_init(MYSQL *mysql)
Description
Create a MYSQL_STMT handle. The handle should be freed with mysql_stmt_close(MYSQL_STMT *).
The mysql_stmt_init()
function returns a pointer to a MYSQL_STMT
. The part saying that it "should be freed" implies that it is dynamically allocated from the heap. The value returned is the memory address (pointer) of this heap memory. To properly free it, the same memory address (pointer value) must be given to mysql_stmt_close()
.
When you use your original MYSQL_STMT prepared = *mysql_stmt_init(&_mysql);
version, you are copying the value of the MYSQL_STMT
returned into the local variable prepared
, which resides on the stack. When you take the address of this to give to mysql_stmt_close(&prepared)
you are not giving the original memory address from the heap that you were given by mysql_stmt_init()
.
Upvotes: 0
Reputation: 14046
From the manual for mysql_stmt_close
:
Closes the prepared statement. mysql_stmt_close() also deallocates the statement handle pointed to by stmt.
If you do:
MYSQL_STMT prepared = *mysql_stmt_init(&_mysql);
mysql_stmt_close(&prepared);
That passes a pointer to a stack variable into the mysql_stmt_close
function which will then try to free
it resulting in the error you saw. Instead, you must pass in the original pointer returned by mysql_stmt_init
as shown in your first code snippet. mysql_stmt_init
returns dynamic memory (obtained via malloc
or similar function) which then needs to be freed by mysql_stmt_close
.
Upvotes: 1