C 堆栈管理器项目:文件 I/O 存在系统调用问题

C Stack Manager Project: file I/O with syscalls problems

我目前正在研究一个模拟堆栈的 c 库(使用链表)。

堆栈必须能够管理任何数据类型。

它还必须能够将其内容写入文件然后检索它们。这是我遇到问题的地方。当我将原始堆栈与我存储在文件中的堆栈进行比较时,数据不一样。

代码如下:

writeRead.c

#include <stdio.h>

#include "stack.h"

#define NODES 3

struct my_data {
    int val;
    char name[60];
};

int main() {
    struct my_stack *s1, *fs1;
    struct my_data *data, *data1, *data2;

    // Initialize Stack
    s1 = my_stack_init(sizeof(struct my_data));
    // Initialize data and push to stack
    for (int i = 0; i < NODES; i++) {
        data = malloc(sizeof(struct my_data)); // We must allocate static memory
        data->val = i;
        sprintf(data->name, "Value %d", i);
        if (my_stack_push(s1, data)) {
            puts("Error in my_stack_push()");
            exit(1);
        }
        printf("New node in s1: (%d, %s)\n", data->val, data->name);
    }

    // Write Stack to file
    if (my_stack_write(s1, "/tmp/my_stack.data") == -1) {
        puts("Error in my_stack_write (s1)");
        exit(1);
    }

    // Read Stack from file
    fs1 = my_stack_read("/tmp/my_stack.data");
    if (!fs1) {
        puts("Error in my_stack_read (fs1)");
        exit(1);
    }


    // Compare data of stack s1 (memory) and fs1 (file)
    while ((data1 = my_stack_pop(s1))) {
        printf("FS1 len. %d\n",my_stack_len(fs1));
        data2 = my_stack_pop(fs1);
        printf("Node of s1: (%d, %s)\t", data1->val, data1->name);
        printf("Node of fs1: (%d, %s)\n", data2->val, data2->name);
        if (!data2 || data1->val != data2->val || my_strcmp(data1->name, data2->name)) {
            printf("Data in s1 and fs1 are not the same.\n (data1->val: %d <> data2->val: %d) o (data1->name: %s <> data2->name: "
                   "%s)\n",
                   data1->val, data2->val, data1->name, data2->name);
            exit(1);
        }
    }

    return 0;


}

stack.h

#include <fcntl.h>     /* Modos de apertura de función open()*/
#include <stdlib.h>    /* Funciones malloc(), free(), y valor NULL */
#include <sys/stat.h>  /* Permisos función open() */
#include <sys/types.h> /* Definiciones de tipos de datos como size_t*/
#include <unistd.h>    /* Funciones read(), write(), close()*/

struct my_stack_node {
    void *data;
    struct my_stack_node *next;
};

struct my_stack {
    int size;
    struct my_stack_node *first;
};

int my_strcmp(const char *str1, const char *str2);
struct my_stack *my_stack_init(int size);
int my_stack_push(struct my_stack *stack, void *data);
void *my_stack_pop(struct my_stack *stack);
int my_stack_len(struct my_stack *stack);
struct my_stack *my_stack_read(char *filename);
int my_stack_write(struct my_stack *stack, char *filename);
int my_stack_purge(struct my_stack *stack);

stack.c

#include <stdio.h>
#include "stack.h"

int my_strcmp(const char *str1, const char *str2) {
    int restultatCmp = *str1++ - *str2++;
    //printf("ResultatCmp : %d \n", restultatCmp);
    while(*str1++ && *str2++ && restultatCmp == 0) {
        restultatCmp = *str1 - *str2;
    }
    return restultatCmp;
}

struct my_stack *my_stack_init(int dataSize) {
    struct my_stack *stack = malloc(sizeof(struct my_stack));
    stack -> first = NULL;
    stack -> size = dataSize;
    return stack;
}

int my_stack_push(struct my_stack *stack, void *dataIn) {
    struct my_stack_node *nodeToPush;
    nodeToPush = malloc(sizeof(struct my_stack_node));

    if(stack == NULL && sizeof(dataIn)> 0){
        printf("Null Stack or data size error.\n");
        //la pila debe existir
        return -1;
    } 
    else {
        nodeToPush -> data = dataIn;
        if(stack -> first == NULL) {
            nodeToPush -> next = NULL;
            stack -> first = nodeToPush;

        }
        else {
            nodeToPush -> next = stack -> first;
            stack -> first = nodeToPush;  
        }
    }
    return 0;
}

void *my_stack_pop(struct my_stack *stack) {
    if(stack -> first == NULL) {
        return NULL;
    }
    struct my_stack_node *nodeToDelete = stack -> first;
    void *data = nodeToDelete -> data;
    stack -> first = nodeToDelete -> next;
    free(nodeToDelete);

    return data; 
}

int my_stack_len(struct my_stack *stack) {
    int numNodes = 0;
    struct my_stack_node *currentElement = stack -> first;
    while(currentElement != NULL) {
        numNodes++;
        currentElement = currentElement ->next;
    }
    return numNodes;
}

void recursiveWrite(struct my_stack_node *nodo, int fileDesc, int sizeData) {
    if(nodo ->next != NULL) recursiveWrite(nodo -> next,fileDesc,sizeData);
    if(write(fileDesc, nodo -> data, sizeData)== -1){
        printf("Error de escritura\n");
        return;// error escritura.
    }
}

int my_stack_write(struct my_stack *stack, char *filename) {
    struct my_stack_node *currentNode = stack -> first;
    int fileDesc = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
    if(fileDesc == -1) {
        return -1; // Error open();
    }
    if(write(fileDesc, &stack -> size, sizeof(stack -> size)) == -1){
        return -1; // Error write();
    }
    int sizeData = stack -> size;
    recursiveWrite(currentNode,fileDesc,sizeData);
    close(fileDesc);

    return my_stack_len(stack);
}

struct my_stack *my_stack_read(char *filename) {
    int fileDesc = open(filename, O_RDONLY, S_IRUSR);
    if(fileDesc == -1) {
        return NULL; // Error open();
    }
    char *buffer = malloc(sizeof(int));
    int readBytes;
    if((readBytes = read(fileDesc, buffer, sizeof(int))) == -1){
        printf("Error reading data size.\n");
        return NULL;
    }
    int dataSize = 0;
    dataSize = (int) *buffer; // parse data Size from buffer.
    struct my_stack *stack; 
    stack = malloc(sizeof(struct my_stack));
    stack = my_stack_init(dataSize); // initialize Stack
    buffer = realloc(buffer, stack -> size);
    if(buffer == NULL){
        return NULL;
    }
    else{
        while(read(fileDesc, buffer, stack -> size) > 0) {
            if((my_stack_push(stack,buffer))== -1){
                printf("Error en my_stack_read: Push error.\n");
                return NULL;
            }

        }
    close(fileDesc);
    return stack;
    }   
}

对不起,我尽量简化了示例。

输出:

New node in s1: (0, Value 0)
New node in s1: (1, Value 1)
New node in s1: (2, Value 2)
FS1 len. 3
Node of s1: (2, Value 2)        Node of fs1: (2, Value 2)
FS1 len. 2
Node of s1: (1, Value 1)        Node of fs1: (2, Value 2)
Data in s1 and fs1 are not the same.
 (data1->val: 1 <> data2->val: 2) o (data1->name: Value 1 <> data2->name: Value 2)

预期输出:

New node in s1: (0, Value 0)
New node in s1: (1, Value 1)
New node in s1: (2, Value 2)
FS1 len. 3
Node of s1: (2, Value 2)        Node of fs1: (2, Value 2)
FS1 len. 2
Node of s1: (1, Value 1)        Node of fs1: (1, Value 1)
FS1 len. 1
Node of s1: (0, Value 0)        Node of fs1: (0, Value 0)

我几乎可以确定文件写入是正确的。用十六进制编辑器检查,应该是正确的。

所以我的猜测是我的错误在于读取文件。

忘了说项目的一个限制是I/O的系统调用是强制性的。

非常感谢任何帮助。

提前致谢。

编辑1:

按照@AndrewHenle 的建议更改了 *my_stack_read(),输出仍然不是预期的。

struct my_stack *my_stack_read(char *filename) {
    int fileDesc = open(filename, O_RDONLY, S_IRUSR);
    if(fileDesc == -1) {
        return NULL; // Error open();
    }
    char *buffer = malloc(sizeof(int));
    ssize_t readBytes;
    readBytes = read(fileDesc, buffer, sizeof(int));
    if(readBytes == -1) {
        return NULL;
    }
    int dataSize = 0;
    dataSize = (int) *buffer; // parse data Size from buffer.
    struct my_stack *stack; 
    stack = malloc(sizeof(struct my_stack));
    stack = my_stack_init(dataSize); // initialize Stack
    buffer = realloc(buffer, stack -> size);
    if(buffer == NULL){
        return NULL;
    }
    else{
        while(read(fileDesc, buffer, stack -> size) > 0) {
            int push = my_stack_push(stack,buffer);
            if(push == -1){
                printf("Error en my_stack_read: Push error.\n");
                return NULL;
            }

        }
    close(fileDesc);
    return stack;
    }   

您正在以递归方式写入堆栈。下面的函数首先将堆栈的 last 元素写入文件。它写入数据相反。

void recursiveWrite(struct my_stack_node *nodo, int fileDesc, int sizeData) {
    if(nodo ->next != NULL) recursiveWrite(nodo -> next,fileDesc,sizeData);
    if(write(fileDesc, nodo -> data, sizeData)== -1){
        printf("Error de escritura\n");
        return;// error escritura.
    }
}

要按正确顺序写入数据,应在write函数之后调用递归函数。我还更改了 write 函数以将其从 if 条件中删除。

void recursiveWrite(struct my_stack_node *nodo, int fileDesc, int sizeData) {
   int ret;
   ret = write(fileDesc, nodo -> data, sizeData); 
   if(ret == -1){
        printf("Error de escritura\n");
        return;// error escritura.
    }
    if(nodo ->next != NULL) recursiveWrite(nodo -> next,fileDesc,sizeData);
}

解法:

我发现我的错误在 *my_stack_read:

while(read(fileDesc, buffer, stack -> size) > 0) {
        int push = my_stack_push(stack,buffer);
        if(push == -1){
            printf("Error en my_stack_read: Push error.\n");
            return NULL;
        }
        buffer = malloc(stack -> size);
    }

buffer = malloc(stack -> size);我在for循环外分配了内存,后面的读取我没有分配。

我认为读取会使用相同的方向覆盖它的内容,但似乎这是不可能的。

谁能解释一下原因?

谢谢大家