Ошибка сегментации при использовании sprintf

fs99
Дата: 06.10.2014 18:49:30
Добрый день.

имеется функция:
void *thread_func(void *arg)
{
	int loc_id = (int) arg;
	//char loc_id_ch = (char) loc_id;
	MYSQL f_mysql;                            // Дескриптор соединения
	MYSQL_RES *f_res;                         // Дескриптор результирующей таблицы
	MYSQL_ROW f_row;
	f_mysql = db_connect();
	char f_query;
	sprintf(&f_query,  "SELECT id, uid FROM sensors WHERE enabled = 1 AND id = %d", loc_id);
	f_res = db_resource(f_mysql, &f_query);
	if (mysql_num_rows(f_res) > 0)
	{
		f_row = mysql_fetch_row(f_res);
		printf("UID = %s \n", f_row[1]);
	} else {
		printf("NO ROWS");
	}
	mysql_free_result(f_res); // Очищаем результаты
	mysql_close(&f_mysql); // Закрываем соединение
	sleep(1);
	return NULL;
}

все она хорошо работала, пока не вставил вот такую строку:
sprintf(&f_query, "SELECT id, uid FROM sensors WHERE enabled = 1 AND id = %d", loc_id);

после этого выдает следующее при запуске приложения:


calligraff@calligraff-deb:~$ g++ -Wall -Wextra -Werror -o prog `mysql_config --cflags` main.cpp `mysql_config --libs`
calligraff@calligraff-deb:~$ ./prog
UID = 28.76735D050000
Ошибка сегментирования
calligraff@calligraff-deb:~$

Помогите пожалуйста.

P.S. программирую на С++ не более 3 дней.

Спасибо.

ниже представлен весь код программы (на всякий случай):

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <mysql/mysql.h>
#include <pthread.h>
#include <unistd.h>
using namespace std;

MYSQL db_connect()
{
	// Описание дескрипторов
	MYSQL mysql;
	// Описание переменных
	char host[] = "localhost";             // Хост
	char user[] = "user1";             // Пользователь
	char passwd[] = "passwd1";     // Пароль
	char db[] = "base1";           // Название базы данных
	int port = 3306;                        // Порт

	// Инициализация
	mysql_init(&mysql);

	// Соединение
	if (!mysql_real_connect(&mysql, host, user, passwd, db, port, NULL, 0))
	{
		fprintf(stderr, "Failed to connect to database: Error: %s\n", mysql_error(&mysql));
	} else {
		//printf("Deamon connect to database is ok.\n");
	}

	return mysql;
}

MYSQL_RES *db_resource(MYSQL mysql, const char query[])
{
	// Описание дескрипторов
	MYSQL_RES *res;
	if (mysql_query(&mysql, query) > 0) // запорс. Если ошибок нет, то продолжаем работу
	{
		// Если была ошибка, ...
		printf("%s", mysql_error(&mysql));  // ... вывдем ее
		return 0; // и завершим работу
	}

	res = mysql_store_result(&mysql); // Берем результат,

	return res;
}

void *thread_func(void *arg)
{
	int loc_id = (int) arg;
	//char loc_id_ch = (char) loc_id;
	MYSQL f_mysql;                            // Дескриптор соединения
	MYSQL_RES *f_res;                         // Дескриптор результирующей таблицы
	MYSQL_ROW f_row;
	f_mysql = db_connect();
	char f_query;
	sprintf(&f_query,  "SELECT id, uid FROM sensors WHERE enabled = 1 AND id = %d", loc_id);
	f_res = db_resource(f_mysql, &f_query);
	if (mysql_num_rows(f_res) > 0)
	{
		f_row = mysql_fetch_row(f_res);
		printf("UID = %s \n", f_row[1]);
	} else {
		printf("NO ROWS");
	}
	mysql_free_result(f_res); // Очищаем результаты
	mysql_close(&f_mysql); // Закрываем соединение
	sleep(1);
	return NULL;
}

void start_thread(MYSQL_RES *res)
{
	// Описание дескрипторов
	MYSQL_ROW row;

	pthread_attr_t threadAttr;
	pthread_attr_init(&threadAttr);
	pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);

	unsigned num_rows = mysql_num_rows(res); //***** и количество строк.

	pthread_t thread[num_rows];

	int id[num_rows];
	
	for (unsigned i = 0; i < num_rows; i++)
	{
		row = mysql_fetch_row(res);
		id[i] = atoi(row[0]);
		pthread_create(&thread[i], &threadAttr, thread_func, (void*)id[i]);
	}

}

int main(){
	// Описание дескрипторов
	MYSQL mysql;				// Дескриптор соединения
	MYSQL_RES *res;				// Дескриптор результирующей таблицы

	mysql = db_connect();
	res = db_resource(mysql, "SELECT id, uid FROM sensors WHERE enabled = 1");
	start_thread(res);
	mysql_free_result(res); // Очищаем результаты
	mysql_close(&mysql); // Закрываем соединение

	sleep(10);

	return 0;
}
NekZ
Дата: 06.10.2014 18:54:59
fs99,

int loc_id = (int) arg;

Это вообще подозрительно -- присваивать адрес в качестве значения переменной типа int

int loc_id = * arg;

Так правильнее.

char f_query;
sprintf(&f_query,  "SELECT id, uid FROM sensors WHERE enabled = 1 AND id = %d", loc_id);


Вы пытаетесь всю строчку запихать в 1 символ
Правильнее было бы

char f_query[256]; // размер сами подбирайте или юзайте оператор new
sprintf(f_query,  "SELECT id, uid FROM sensors WHERE enabled = 1 AND id = %d", loc_id);
fs99
Дата: 06.10.2014 18:59:39
при замене
int loc_id = (int) arg;

на
int loc_id = * arg;


результат компилирования:

main.cpp: In function ‘void* thread_func(void*)’:
main.cpp:55:17: error: ‘void*’ is not a pointer-to-object type

-----------------------------------------

при
char f_query[256]; // размер сами подбирайте или юзайте оператор new
sprintf(f_query,  "SELECT id, uid FROM sensors WHERE enabled = 1 AND id = %d", loc_id);


результат:

main.cpp: In function ‘void* thread_func(void*)’:
main.cpp:66:39: error: cannot convert ‘char (*)[256]’ to ‘const char*’ for argument ‘2’ to ‘MYSQL_RES* db_resource(MYSQL, const char*)’

на самом деле как только не пробовал - всегда какая-нить ошибка.
fs99
Дата: 06.10.2014 19:16:39
Вариантов нет???
fs99
Дата: 06.10.2014 19:21:41
прошу прощения!

char f_query[256]; // размер сами подбирайте или юзайте оператор new
sprintf(f_query,  "SELECT id, uid FROM sensors WHERE enabled = 1 AND id = %d", loc_id);

верное решение.. там ошибка о другом выскакивала.

а вот int loc_id = * arg; нехотит
NekZ
Дата: 06.10.2014 19:27:13
fs99,

Ну так сделай reinterpret_cast:

int loc_id = * reinterpret_cast< int * >( arg );
fs99
Дата: 06.10.2014 19:29:15
NekZ
fs99,

Ну так сделай reinterpret_cast:

int loc_id = * reinterpret_cast< int * >( arg );


Ошибка сегментирования
Anatoly Moskovsky
Дата: 06.10.2014 19:33:18
fs99,
Вы гаданием что-ли программируете?

Вот тут вы преобразуете int в void*
pthread_create(&thread[i], &threadAttr, thread_func, (void*)id[i]);


Значит тут надо обратно преобразовать
int loc_id = (int)arg;


Хотя конечно по большому счету никто не обещал что void* может вместить int или наоборот.
Но на практике указатель обычно не меньше целого. Так что сойдет.
fs99
Дата: 06.10.2014 19:39:35
:)


спасибо.

Я же говорил, всего 3 дня на Си пытаюсь что-то написать :)
mayton
Дата: 06.10.2014 20:17:48
Вот так вот. С++ за 3 дня. С потоками.