В качестве упражнения, в настоящее время я работаю над проектом: личная текстовая база данных (следовательно, набор (личных и не) данных, расположенных в файле как своего рода «база данных»), управляемая с языком программирования C.
Я решил сохранить все функции управления в файле .h
, а основные функции (те, которые взаимодействуют с пользователем, владельцем базы данных) в файле .c
.
Файл .h
еще не завершен, но я медленно тестирую каждую функцию, чтобы убедиться, что они работают правильно.
В частности, это пугает меня из-за того, что я не могу найти причину, по которой куча переполняется (если она действительно переполняется...).
Вот полный код: (Заинтересованная функция называется «initobj». Хотя я поделился полным кодом, думая, что это может быть полезно понять)
#include <time.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#if defined(_WIN32)
#define PATH "C:\\Database\\"
#elif defined(_WIN64)
#define PATH "C:\\Database\\"
#elif defined(__linux__)
#define PATH "/Database/"
#else
#define PATH NULL
#endif
struct user{
unsigned int uid;
char *username;
char *password;
};
struct file{
unsigned int uid;
char *filename;
char *content;
};
char *initpath(void){
char filename[] = "Database.txt";
char *path = (char *)malloc(sizeof(char) * strlen(PATH) + 1);
if (path != NULL){
strcpy(path, PATH);
mkdir(path);
strcat(path, filename);
return path;
}
else
return NULL;
}
int initobj(struct user *elem, unsigned uid, char *username, char *password){
elem->uid = uid;
if ((elem->username = (char *)malloc(sizeof(char) * strlen(username) + 1)) != NULL)
strcpy(elem->username, username);
else
return -1;
if ((elem->password = (char *)malloc(sizeof(char) * strlen(password) + 1)) != NULL)
strcpy(elem->password, password); //Password is copied into the structure as a normal string. Future updata: encrypting the password
else
return -1;
return 0;
}
int insobj(int database, struct user elem){}
int checkid(int database, unsigned int id){}
int checkusr(int database, char *username){}
int checkpasw(int database, char *password){}
Вместо этого приведен основной код функции:
#include <time.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "database.h"
struct user playground;
int main(int argc, char *argv[]){
srand(time(0));
int err;
struct user *p = &playground;
char *filepath = initpath();
if (filepath != NULL && argc == 3){
if ((err = initobj(p, (rand() % 999), argv[1], argv[2])) == 0)
printf("%u, %s, %s <- Data inserted.\n", p->uid, p->username, p->password);
else
printf("[DEBUG]: From function 'initobj' : %d.\n", err);
}
else
fprintf(stderr, "%s: Not enought arguments.\n", argv[0]);
}
Программа продолжает возвращать мне -1:
C:\Users\Computer\Desktop\ACCESS\Database\lib>dat username password
[DEBUG]: From function 'initobj' : -1.
Следовательно, malloc не может выделить место в голове. Я просто не понимаю, почему.
Будет ли работать, если заменить strlen(PATH)
на (strlen(PATH) + strlen(Filename))
?
Большинство функций устанавливают более конкретный код ошибки в errno
, когда возвращаемое значение указывает на ошибку. Вы можете использовать, например. perror("malloc (username)")
для отображения сообщения об ошибке. Вы написали: «Я решил сохранить все функции управления в файле .h, а основные функции (те, которые взаимодействуют с пользователем, владельцем базы данных) в файле .c». Кажется, вы неправильно понимаете назначение файлов .c и .h. Файл .h должен содержать только объявления, например. прототипы функций. Реализация должна быть в соответствующем файле .c. Ваша программа может быть скомпилирована более чем из одного файла .c.
@Bodo В стороне: «Большинство функций устанавливают более конкретный код ошибки в errno, когда возвращаемое значение указывает на ошибку». преувеличивает. В библиотеке C указано несколько функций, которые устанавливают errno
. malloc()
не указан для установки errno
. Возможно, вы думаете о каком-то специфичном для реализации поведении? Но так как код использует нестандартные mkdir()
, ваше предложение применимо больше.
KmerPadreDiPdor, обратите внимание, что rand() % 999
приводит к значениям [0...998], а не [0...999].
Заголовки должны быть зарезервированы только для объявлений. Не помещайте тела функций в заголовочный файл. Однако совершенно нормально разделить ваши функции между несколькими файлами .c, и в этом случае вы, вероятно, захотите, чтобы объявления (только) по крайней мере для некоторых из них отображались в заголовочном файле.
fyi strdup
объединяет malloc и strcpy, что делает код более понятным
По крайней мере, эти проблемы:
Код не может выделить достаточно места@ Джонни Мопп
char filename[] = "Database.txt";
char *path = (char *)malloc(sizeof(char) * strlen(PATH) + 1); // Wrong size & sense
if (path != NULL){
strcpy(path, PATH);
mkdir(path);
strcat(path, filename); // !! Undefined behavior (UB) !!
return path;
}
С UB strcat(path, filename);
остальная часть кода не имеет значения.
Вместо
Учет как PATH
, так и filename
Литье не нужно.
Масштабирование на sizeof(char) * strlen(PATH) + 1
должно было быть sizeof(char) * (strlen(PATH) + 1)
. sizeof(char)
равен 1 и тоже не нужен.
char filename[] = "Database.txt";
// PATH filename minus its \0 \0
char *path = malloc(strlen(PATH) + (sizeof filename - 1) + 1);
mkdir()
может не получиться
Лучший код проверит mkdir()
успех.
if (mkdir(path)) {
Handle_failure();
}
strcat(path, filename);
Вы выделяете достаточно места только дляPATH
, но затем пытаетесь добавитьfilename
.