如何理解堆是否已满以及为什么 malloc 保持 return NULL?

How to understand if Heap is full and why malloc keeps return NULL?

作为一个练习,我目前正在做一个项目:一个基于个人文本的数据库(因此是(个人和非)数据的集合,作为一种“数据库”排列在一个文件中),使用 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]);

}

程序让return我-1:

C:\Users\Computer\Desktop\ACCESS\Database\lib>dat username password
[DEBUG]: From function 'initobj' : -1. 

因此意味着 malloc 无法在头部分配 space。我只是不明白为什么。

至少这些问题:

代码未能分配足够的 space @ 强尼莫普

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;
}

有了strcat(path, filename);的UB,其余代码无关

相反

  • 同时考虑 PATHfilename

  • 不需要转换。

  • 缩放 sizeof(char) * strlen(PATH) + 1 应该是 sizeof(char) * (strlen(PATH) + 1)sizeof(char) 为 1,也不需要。

    char filename[] = "Database.txt";
    //                     PATH        filename minus its [=11=]   [=11=]
    char *path = malloc(strlen(PATH) + (sizeof filename - 1) + 1);
    

mkdir()可能会失败

更好的代码将测试 mkdir() 成功。

if (mkdir(path)) {
  Handle_failure();
}