Segmentation fault при выполнении сортировки qsort - C (СИ)

Узнай цену своей работы

Формулировка задачи:

Пишу для изучения си программку, типа базы данных. Данные хранятся в массиве структур, и когда я делаю qsort для этого массива, происходит segmetation fault. Когда проверяю в gdb для массива из 2-х элементов функция сравнения вызывается почему-то два раза, и во второй раз последний элемент массива сравнивается с несуществующим. Собственно нужна подсказка, почему так происходит ? Вот код:
Листинг программы
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include <string.h>
  5. #include <stdbool.h>
  6. #include <stddef.h>
  7. typedef struct
  8. {
  9. int id;
  10. int set;
  11. char* name;
  12. char* email;
  13. } userdata;
  14. typedef struct
  15. {
  16. size_t max_rows;
  17. size_t max_strlen;
  18. userdata* rows;
  19. } database;
  20. typedef struct
  21. {
  22. FILE* file;
  23. database* db;
  24. char mode;
  25. } connection;
  26. bool id_too_big(size_t id, size_t max_row)
  27. {
  28. return id >= max_row;
  29. }
  30. bool is_legal_act(const char action)
  31. {
  32. return (action == 'c' || action == 's' || action == 'g' || action == 'l' || action == 'd' || action == 'f');
  33. }
  34. void free_row(userdata* u)
  35. {
  36. if(u && u->set)
  37. {
  38. if(u->name) free(u->name);
  39. if(u->email) free(u->email);
  40. }
  41. }
  42. void free_db(database* db)
  43. {
  44. if(!db) return;
  45. if(!db->rows) return;
  46. for(size_t i = 0; i < db->max_rows; i++)
  47. {
  48. free_row(&db->rows[i]);
  49. }
  50. free(db->rows);
  51. free(db);
  52. }
  53. void connection_close(connection* c)
  54. {
  55. if(!c) return;
  56. if(c->file) fclose(c->file);
  57. free_db(c->db);
  58. free(c);
  59. }
  60. void die(const char* msg, connection *c)
  61. {
  62. connection_close(c);
  63. if(errno)
  64. {
  65. perror(msg);
  66. }
  67. else
  68. {
  69. printf("ERROR: %s\n", msg);
  70. }
  71. exit(EXIT_FAILURE);
  72. }
  73. void database_init(connection* c, size_t max_rows, size_t max_strlen)
  74. {
  75. c->db->max_rows = max_rows;
  76. c->db->max_strlen = max_strlen;
  77. c->db->rows = calloc(max_rows, sizeof(userdata));
  78. for(size_t i = 0; i < max_rows; i++)
  79. {
  80. userdata *u = &c->db->rows[i];
  81. u->id = i;
  82. u->set = 0;
  83. }
  84. }
  85. bool database_row_load(userdata *u, size_t str_len, FILE* f)
  86. {
  87. size_t rc = fread(u, sizeof(userdata), 1, f);
  88. if(rc != 1) return false;
  89. if(!u->set) return true;
  90. u->name = malloc(str_len);
  91. memset(u->name, 0, str_len);
  92. rc = fread(u->name, str_len, 1, f);
  93. if(rc != 1) return false;
  94. u->name[str_len-1] = '\0';
  95. u->email = malloc(str_len);
  96. memset(u->email, 0, str_len);
  97. rc = fread(u->email, str_len, 1, f);
  98. if(rc != 1) return false;
  99. u->email[str_len-1] = '\0';
  100. return true;
  101. }
  102. void database_load(connection* c)
  103. {
  104. size_t readed = fread(c->db, sizeof(database), 1, c->file);
  105. if(readed != 1) die("Unable to read file", c);
  106. database_init(c, c->db->max_rows, c->db->max_strlen);
  107. for(size_t i = 0; i < c->db->max_rows; i++)
  108. {
  109. if(!database_row_load(&c->db->rows[i], c->db->max_strlen, c->file)) die("Unable to read db content", c);
  110. }
  111. }
  112. bool database_row_save(userdata *u, size_t str_len, FILE* f)
  113. {
  114. size_t wc = fwrite(u, sizeof(userdata), 1 , f);
  115. if(wc != 1) return false;
  116. if(!u->set) return true;
  117. wc = fwrite(u->name, str_len, 1, f);
  118. if(wc != 1) return false;
  119. wc = fwrite(u->email, str_len, 1, f);
  120. if(wc != 1) return false;
  121. return true;
  122. }
  123. void database_save(connection *c)
  124. {
  125. c->file = freopen(NULL, "w", c->file);
  126. size_t written = fwrite(c->db, sizeof(database), 1, c->file);
  127. if(written != 1) die("Unable to save database", c);
  128. for(size_t i = 0; i < c->db->max_rows; i++)
  129. {
  130. if(!database_row_save(&c->db->rows[i], c->db->max_strlen, c->file)) die("Unable to save database", c);
  131. }
  132. }
  133. void database_row_print(userdata *row)
  134. {
  135. if(!row->set) return;
  136. printf("Row info:\tid: %2d name: %s email: %s\n", row->id, row->name, row->email);
  137. }
  138. void database_list(connection *c)
  139. {
  140. for(size_t i = 0; i < c->db->max_rows; i++)
  141. {
  142. database_row_print(&c->db->rows[i]);
  143. }
  144. }
  145. userdata* database_row_get(connection *c, size_t id)
  146. {
  147. if(id_too_big(id, c->db->max_rows)) die("No such ID in database", c);
  148. return &c->db->rows[id];
  149. }
  150. void database_row_set(connection *c, size_t id, const char *name, const char *email)
  151. {
  152. if(id >= c->db->max_rows) die("No such ID in database", c);
  153. userdata *u = &c->db->rows[id];
  154. if(u->set == 1) die("ID already exist. Delete it first",c);
  155. u->set = 1;
  156. u->name = malloc(c->db->max_strlen);
  157. strncpy(u->name, name, c->db->max_strlen);
  158. u->name[c->db->max_strlen-1] = '\0';
  159. u->email = malloc(c->db->max_strlen);
  160. strncpy(u->email, email, c->db->max_strlen);
  161. u->email[c->db->max_strlen-1] = '\0';
  162. if(!u->name || !u->email) die("Unable to set data", c);
  163. }
  164. connection* connection_open(const char* filename, const char mode)
  165. {
  166. if(!is_legal_act(mode)) die("Wrong action !", NULL);
  167. connection* c = malloc(sizeof(connection));
  168. if(!c)
  169. {
  170. die("Memory error", c);
  171. }
  172. c->db = malloc(sizeof(database));
  173. if(!c->db) die("Unable to initialise database", c);
  174. c->mode = mode;
  175. if(mode == 'c')
  176. {
  177. c->file = fopen(filename, "w");
  178. }
  179. else
  180. {
  181. c->file = fopen(filename, "r+");
  182. database_load(c);
  183. }
  184. return c;
  185. }
  186. void database_create(int argc, char *argv[], connection *c)
  187. {
  188. if(argc != 5) die("Wrong parameter list", c);
  189. size_t max_rows = atoi(argv[3]);
  190. size_t max_strlen = atoi(argv[4]);
  191. database_init(c, max_rows, max_strlen);
  192. database_save(c);
  193. printf("Database: %s, successfully created !\n", argv[1]);
  194. }
  195. void database_set(int argc, char *argv[], connection *c)
  196. {
  197. if(argc != 6) die("Wrong parameter list", c);
  198. size_t id = atoi(argv[3]);
  199. if(id_too_big(id, c->db->max_rows)) die("Too big ID", c);
  200. database_row_set(c, id, argv[4], argv[5]);
  201. database_save(c);
  202. }
  203. void database_get(int argc, char *argv[], connection *c)
  204. {
  205. if(argc != 4) die("Wrong parameter list", c);
  206. size_t id = atoi(argv[3]);
  207. database_row_print(database_row_get(c, id));
  208. }
  209.  
  210. void database_delete(int argc, char *argv[], connection *c)
  211. {
  212. if(argc != 4) die("Wrong parameter list", c);
  213. size_t id = atoi(argv[3]);
  214. if(id_too_big(id, c->db->max_rows)) die("Too big ID", c);
  215. userdata *u = &c->db->rows[id];
  216. if(!u->set) die("Record is empty", c);
  217. free_row(u);
  218. u->set = 0;
  219. database_save(c);
  220. }
  221. bool field_exist(const char *fld)
  222. {
  223. return (strcmp(fld, "name") == 0 || (strcmp(fld, "email") == 0));
  224. }
  225. int userdata_name_compare(const void* u1, const void* u2)
  226. {
  227. const userdata *tmp1 = (userdata *)u1;
  228. const userdata *tmp2 = (userdata *)u2;
  229. return strcmp(tmp1->name, tmp2->name);
  230. }
  231. userdata *database_row_find(connection *c, const char *search_field, const char *search_value)
  232. {
  233. if(!field_exist(search_field)) die("Field you trying to search not exist!", c);
  234. size_t rows_size = sizeof(userdata)*(c->db->max_rows);
  235. userdata *row;
  236. userdata k;
  237. if(strcmp(search_field, "name") == 0)
  238. {
  239. qsort(c->db->rows, c->db->max_rows, sizeof(userdata), userdata_name_compare);
  240. k.name = malloc(c->db->max_strlen);
  241. strncpy(k.name, search_value, c->db->max_strlen);
  242. k.name[c->db->max_strlen-1] = '\0';
  243. row = bsearch(&k, c->db->rows, c->db->max_rows, rows_size, userdata_name_compare);
  244. free(k.name);
  245. }
  246. if(strcmp(search_field, "email") == 0)
  247. {
  248. }
  249. return row;
  250. }
  251. void database_find(int ac, char *av[], connection *c)
  252. {
  253. if(ac < 5) die("Search string example: db <db file> f <field_name> <value>", c);
  254. userdata *u = database_row_find(c, av[3], av[4]);
  255. if(!u)
  256. {
  257. printf("Row with \"%s\" like %s not found", av[3], av[4]);
  258. return;
  259. }
  260. database_row_print(u);
  261. }
  262. int main(int argc, char *argv[])
  263. {
  264. if(argc < 3) die("Usage: db <db file> <action> [action params]", NULL);
  265. char action = argv[2][0];
  266. connection *c = connection_open(argv[1],action);
  267. switch(action)
  268. {
  269. case 'c':
  270. database_create(argc, argv, c);
  271. break;
  272. case 's':
  273. database_set(argc, argv, c);
  274. break;
  275. case 'g':
  276. database_get(argc, argv, c);
  277. break;
  278. case 'l':
  279. database_list(c);
  280. break;
  281. case 'd':
  282. database_delete(argc, argv, c);
  283. break;
  284. case 'f':
  285. database_find(argc, argv, c);
  286. break;
  287. default:
  288. die("Available commands: c - create, s - set, g - get, l - list, f - find", c);
  289. break;
  290. }
  291. connection_close(c);
  292. return EXIT_SUCCESS;
  293. }
Если что-то не понятно или нужно дополнить вопрос, пишите p.s. под линукс с gcc компилируется без ошибок и ворнингов

Решение задачи: «Segmentation fault при выполнении сортировки qsort»

textual
Листинг программы
  1.    free_row(u);
  2.    u->set = 0;

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

7   голосов , оценка 4.143 из 5

Нужна аналогичная работа?

Оформи быстрый заказ и узнай стоимость

Бесплатно
Оформите заказ и авторы начнут откликаться уже через 10 минут
Похожие ответы