Как ссылаться на char * вместо использования char [] при использовании mysql_stmt_prepare - PullRequest
0 голосов
/ 08 июля 2019

При попытке вставить несколько записей, используя C, используя параметр bind, я не могу заставить его работать, используя char * str_data, а затем использую malloc из strdup, чтобы установить «тестовую строку». Я должен определить char str_data[50]. Если я попытаюсь использовать char * str_data и str_data = strdup("teststring"), это заполнит MySQL случайными байтами.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <my_global.h>
#include <mysql.h>

int main(void)
{
    MYSQL *con;
    con = mysql_init(NULL);

    my_bool reconnect = 1;
    mysql_options(con, MYSQL_OPT_RECONNECT, &reconnect);

    if (mysql_real_connect(con, "127.0.0.1", "hidden", "hidden", "hidden", 0, NULL, 0) == NULL) {
        fprintf(stderr, "%s\n", mysql_error(con));
        mysql_close(con);
        exit(0);
    }

    MYSQL_STMT *stmt;
    MYSQL_BIND ps_params[1];
    char str_data[50];
    unsigned long str_length;

    stmt = mysql_stmt_init(con);
    mysql_stmt_prepare(stmt, "INSERT INTO `test` (two) VALUES (?)", strlen("INSERT INTO `test` (two) VALUES (?)"));
    memset(ps_params, 0, sizeof(ps_params));

    ps_params[0].buffer_type = MYSQL_TYPE_STRING;
    ps_params[0].buffer = (char *)&str_data;
    ps_params[0].buffer_length = 50;
    ps_params[0].length = &str_length;
    ps_params[0].is_null = 0;

    mysql_stmt_bind_param(stmt, ps_params);

    str_length = strlen("test string");
    strcpy(str_data, "test string");
    mysql_stmt_execute(stmt);

    mysql_close(con);

}

Может кто-нибудь объяснить мне, почему использование char * str_data и str_data = strdup("teststring") приводит к бессмысленному чтению MySQL?

Edit:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <my_global.h>
#include <mysql.h>

int main(void)
{
    MYSQL *con;
    con = mysql_init(NULL);

    my_bool reconnect = 1;
    mysql_options(con, MYSQL_OPT_RECONNECT, &reconnect);

    if (mysql_real_connect(con, "127.0.0.1", "hidden", "hidden", "hidden", 0, NULL, 0) == NULL) {
        fprintf(stderr, "%s\n", mysql_error(con));
        mysql_close(con);
        exit(0);
    }

    MYSQL_STMT *stmt;
    MYSQL_BIND ps_params[1];
    char * str_data;
    unsigned long str_length;

    stmt = mysql_stmt_init(con);
    mysql_stmt_prepare(stmt, "INSERT INTO `test` (two) VALUES (?)", strlen("INSERT INTO `test` (two) VALUES (?)"));
    memset(ps_params, 0, sizeof(ps_params));

    ps_params[0].buffer_type = MYSQL_TYPE_STRING;
    ps_params[0].buffer = (char *)&str_data;
    ps_params[0].buffer_length = (strlen("test string") + 1);
    ps_params[0].length = &str_length;
    ps_params[0].is_null = 0;

    mysql_stmt_bind_param(stmt, ps_params);

    str_length = strlen("test string");
    str_data = strdup("test string");
    mysql_stmt_execute(stmt);

    mysql_close(con);

}

результат в базе данных: Ð|D =N_

результат в printf("'%s'\n", str_data): 'test string'

Я думаю, что это как-то связано с ps_params[0].buffer = (char *)&str_data; указателем

1 Ответ

0 голосов
/ 08 июля 2019

Вот часть вашего кода, вызывающая проблемы:

ps_params[0].buffer = (char *)&str_data;

.buffer должна указывать на буфер памяти, но она указывает на (неинициализированный) указатель.Тот факт, что вы используете приведение типов, чтобы избавиться от предупреждения компилятора, должен указывать на то, что что-то не так. Никогда, ни при каких обстоятельствах не используйте приведение типов, если только вы не знаете лучше, чем происходит компилятор!

Так что, если str_data указывает на буфер, просто инициализируйте ps_params[0].buffer со значением из str_data вместо адреса из str_data..buffer должен указывать на "то же самое", на которое указывает str_data, а не на str_data.Например:

ps_params[0].buffer = str_data;

Проблема в том, что вы еще не инициализировали str_data.Это указывает на мусор, так что теперь ps_params[0].buffer также указывает на мусор.Поэтому вы должны переместить инициализацию str_data до назначения ps_params[0].buffer:

char * str_data = strdup("test string");
unsigned long str_length = strlen(str_data);

stmt = mysql_stmt_init(con);
mysql_stmt_prepare(stmt, "INSERT INTO `test` (two) VALUES (?)", strlen("INSERT INTO `test` (two) VALUES (?)"));
memset(ps_params, 0, sizeof(ps_params));

ps_params[0].buffer_type = MYSQL_TYPE_STRING;
ps_params[0].buffer = str_data;
ps_params[0].buffer_length = str_len + 1;
ps_params[0].length = &str_length;
ps_params[0].is_null = 0;

mysql_stmt_bind_param(stmt, ps_params);

mysql_stmt_execute(stmt);

// `strdup` calls `malloc`, so we have to free the buffer after use
free(str_data); 

mysql_close(con);

Добавление проверки ошибок во время выполнения оставлено в качестве упражнения для читателя

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...