C在结构中修改数组

我正在用C编写操作系统。我有一个使用结构的基本文件系统。我正在编写命令行,并且想要一个函数来创建一个新文件。我已经设置了一个,但是没有用。该结构初始化良好,但未将其添加到该文件夹​​中。 每个文件都是以下file类型的结构:

typedef struct {
    char** content; // Address of the text in the file
    char* name;     // Filename
    size_t size;    // Included from stddef.h - set by the function
} file;

每个目录都是以下dir类型的结构:

typedef struct {
    file* files[256]; // The files in the directory
    char* name;       // The directory name
    size_t index;     // The index of the next file - basically the length of the files array - starts at 0
} dir;

我的new_file函数如下:

void new(dir* folder,char* name,char* content) { 
    // Folder is a dir* so we can modify the actual struct,not a copy
    file f;
    f.name = name;
    f.content = &content;
    folder -> files[folder -> index] = &f;
    folder -> index++;
}

我是C语言的初学者,但我无法确定问题所在。请帮忙!

更多信息

new函数(基本上):

void new(char* name,char* content,dir* folder) {
    file new = new_file(name,content);
    add_file(folder,new);
}

add_file函数:

void add_file(dir* folder,file f) {
    folder -> files[folder -> dirnum] = f;
    folder -> dirnum++;
}

我调用以尝试读取文件的函数:

char* read(dir* folder,char* name) {
    file f = find_file(*folder,name);
    return f.content;
}

find_file为:

file find_file(folder,name) {
    for (size_t i = 0; i < folder.filenum; i++) {
        file f = *folder.files[i];
        if (strcmp(f.name,name,'\0')) {
            return f;
        }
    }
}

strcmp是我编写的字符串比较函数。
对源代码进行一些修改后,会出现以下错误。 当您运行时(在命令行中):

new hi file // Same as new("hi","file",&root)
open hi // Same as read(&root,"hi")

输出为open hi

当我运行new函数时,folder.files[0]存在。但是,folder.files[0] -> name等于g→。知道为什么吗?

susanlixinyu 回答:C在结构中修改数组

问题是

void new(dir* folder,char* name,char* content) { 
// Folder is a dir* so we can modify the actual struct,not a copy
   file f;
   .......
   folder -> files[folder -> index] = &f;

这里f在局部变量中。

存储地址不是明智的选择。

或者,您可以执行以下两项操作之一

  1. 最简单的方法是声明文件的全局数组并使用它们。 //仅用于测试其非常糟糕的主意,但足够容易地检查其是否可以解决问题。
  2. 正确的方法是使用malloc之类的方法分配内存,并在删除时释放它。

在实际文件系统中,此列表在磁盘上保留。引用最简单的文件系统来研究FAT16

我使用了chans FATFS实现。这很容易理解。并有据可查。

,

我好像您想知道代码的问题。因此,我使用原始答案下方的原因更新了此答案。

由于没有太多信息,也没有使用malloc的能力,因此我只能为您提供这种非常简单的内存管理代码。请注意,这只是一个示例,如果您必须在没有malloc的环境中工作,则必须自己学习内存管理并编写自己的malloc。

请注意,您还可以使用堆栈存储器来创建所有变量。尽管堆栈存储器速度很快,但是堆栈存储器仍然有局限性。

对于下面的代码,它是示例代码。因此,我只使用了最简单的内存管理方法。下面的代码使用mmap()从系统请求内存。

对于代码的内存管理方法,它向系统请求一块内存,以用作空闲内存池。每当任何方法调用requestMem时,它将尝试从系统请求的内存池中获取一块未使用的内存。如果requestMem函数可以从其池中获取一块空闲内存,则它将返回一个指向该空闲内存块开头的指针。返回的指针类型将始终为void类型。除非它无法获得任何内存。在这种情况下,将返回NULL。

大多数注释都写在代码中。另外,我将您的**内容更改为*内容。除此之外,我用普通库的strcmp()替换了您的strcmp()。我还将您的read()重命名为read2()。

请注意,我确实测试了该方法,但没有完全测试,因为它只是一个示例。它只是为了帮助您了解一些有关内存管理的知识。请注意,我没有编写像realloc()这样的用于重新分配内存的方法,也没有编写用于释放每个指针的内存的方法。尽管如此,我的设计方式还是可以为每个指针发明自己的free()。您还可以在每次释放后设计自己的内存碎片整理,方法是将后面的块复制(移动)到正义释放块的空间中。

#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>

#define __PMAX__ 500

typedef struct __membin__ __membin__;
int freebin(__membin__ * bin);
void * _requestMem( size_t size );
void * __requestMem( size_t size );
void * ___requestMem( size_t size );

/* Memory Bin is membin */
__membin__ membin;
/*
 * Use requestMem to request memory from membin.
 * Read the comments from main() to understand more 
 * about requestMem.
 * 
 **/
void * (*requestMem)(size_t) = &_requestMem;

/* 
 * Struct for memory bin
 */
typedef struct __membin__ {
    void * mempage;
    intptr_t from;               /* <- memory page from: inclusive */
    intptr_t to;                 /* <- memory page to: inclusive */

    intptr_t pointer[__PMAX__];  /* <- Pointers */
    intptr_t pTo[__PMAX__];      /* <- Address to for pointer: inclusive */    
    size_t pUsed;                /* <- Pointer used */

    size_t size;                 /* <- Actual size */
    size_t sUsed;                /* <- Size Used */
} __membin__;

/* Free the memory bin */
int freebin(__membin__ * bin){
    int code = munmap(bin->mempage,bin->size);
    if ( code == 0 ){
        bin->size = 0;
    }
    return code;
}

/* 
 * This function initialize the memory bin.
 * This function use mmap to allocate a large memory block with the 
 * size of sysconf(_SC_PAGESIZE) * 20. That memory block is converted
 * to a void pointer then assigned to membin->mempage.
 * 
 * Initial size of membin can be configured to be larger.
 **/
int membinInit(__membin__ * bin){
    size_t initSize = sysconf(_SC_PAGESIZE) * 20;
    bin->mempage = (void *)mmap(NULL,initSize,PROT_READ|PROT_WRITE,MAP_ANON|MAP_PRIVATE,-1,0);

    if (bin->mempage == MAP_FAILED) return 1;  

    bin->from = (intptr_t) bin->mempage;
    bin->to = bin->from + (intptr_t) initSize - 1;

    bin->pUsed = 0;
    bin->size = initSize;
    bin->sUsed = 0;

    return 0;
}

/*
 * On first run,requestMem is assigned to this function _requestMem.
 * After this function initialize the memory bin successfully it will 
 * assign requestMem to be a pointer of function __requestMem. 
 * 
 * On unsuccessful case of membin initialization,requestMem will be a 
 * pointer to the ___requestMem function that always return null.
 *
 */ 
void * _requestMem( size_t size ){
    int code = membinInit(&membin);
    if ( code == 1 ) {
        requestMem = &___requestMem;
        return NULL;
    } 

    requestMem = &__requestMem;
    return __requestMem(size);
}

/*
 * __requestMem is a function that will get a block of memory from the
 * unused portion of memory of membin->mempage. 
 * 
 * If the requested size is larger than what available in membin then 
 * NULL will be returned. 
 * 
 * If the requested size is 0 then a value NULL will also be returned.
 */
void * __requestMem( size_t size ){
    size_t new_sUsed = size + membin.sUsed;
    if ( size == 0 
         || new_sUsed > membin.size 
         || membin.pUsed >= __PMAX__ ) return NULL;

    intptr_t p = membin.from + membin.sUsed;

    membin.pointer[membin.pUsed] = p;
    membin.pTo[membin.pUsed] = p + size - 1;
    membin.pUsed++;

    membin.sUsed = new_sUsed;

    return (void * ) p;
}

/*
 * This function will always return NULL.
 * This function name can be changed to NULL returned function.
 */
void * ___requestMem( size_t size ){
    return NULL;
}

typedef struct {
    char * content; // Address of the text in the file
    char * name;    // Filename
    size_t size;    // Included from stddef.h - set by the function
} file;

typedef struct {
    file * files[256]; // The files in the directory
    char * name;       // The directory name
    size_t index;      // The index of the next file - basically the length of the files array - starts at 0
} dir;

void new_file(dir* folder,char* content);
void add_file(dir* folder,file * f);
char* read2(dir* folder,char* name);
file * find_file(dir * folder,char * name);

void new_file(dir* folder,char * name,char * content){ 
    // Folder is a dir * so we can modify the actual struct,not a copy   
    /*
     * Using requestMem to request a block of memory from membin for f.
     *
     **/
    file * f = (file * ) requestMem(sizeof(file));
    f->name = name;
    f->content = content;
    folder->files[folder->index] = f;
    folder->index++;
}

void add_file(dir* folder,file * f) {
    folder->files[folder->index] = f;
    folder->index++;
}

char * read2(dir * folder,char* name) {
    file * f = find_file(folder,name);
    if ( f != NULL ) return f->content;
    else return NULL;
}

file * find_file(dir * folder,char * name) {
    for (size_t i = 0; i < folder->index; i++) {
        if (strcmp(folder->files[i]->name,name) == 0 ) {
            return folder->files[i];
        }
    }

    return NULL;
}

int main(void) {

    /* Testing membin */
    char * s = requestMem( sizeof(char) * 15 );
    char * s2 = requestMem( sizeof(char) * 24 );

    /* Check for membin size */
    printf("membin size : %zu bytes \n\n",membin.size);
    /* checking if the pointer address of s is equal to the pointer of
     * membin.pointer[0]. They should be equal.
     * 
     * membin.pTo[0] should be the last memory address for s. Of which should
     * be s' address + s' size - 1.
     */
    printf("pointer s: %lld,membin.pointer[0]: %lld,membin.pTo[0]: %lld \n\n",(long long)s,(long long) membin.pointer[0],(long long)membin.pTo[0]);
    /* checking if the pointer address of s2 is equal to the pointer of
     * membin.pointer[1]. They should be equal. Also s2 pointer 
     * should be the value of membin.pTo[0] + 1.
     * 
     * membin.pTo[1] should be the last memory address for s2. Of which should
     * be s2's address + s2's size - 1.
     */
    printf("pointer s2: %lld,membin.pointer[1]: %lld,membin.pTo[1]: %lld \n\n",(long long)s2,(long long)membin.pointer[1],(long long)membin.pTo[1]);
    /* 
     * If requestMem worked correctly,when membin is not yet initialized
     * requestMem will have same address of _requestMem.
     * 
     * If after first run sucessful and membin is initialized requestMem
     * will have the same address as __requestMem.
     * 
     * If initialize of membin fail,requestMem will have the
     * same address as ___requestMem.
     */
    printf("requestMem:    %p\
          \n_requestMem:   %p\
          \n__requestMem:  %p\
          \n___requestMem: %p\
          \n\n",requestMem,_requestMem,__requestMem,___requestMem);

    /* File Testing */
    dir root;
    root.name = "root";
    root.index = 0;

    new_file(&root,"Hi","I am the content.");

    file * foundFile = find_file(&root,"Hi");
    if ( foundFile != NULL ){
      printf("Found the file:\n");
      printf("Name: %s\n",foundFile->name);
      printf("Content: %s\n\n",foundFile->content);
    }
    /* End File Testing*/


    /* Add all the sizes together to see if the size used in membin is right.*/
    printf("Size of struct file: %zu bytes\n",sizeof(file));    
    printf("membin sUsed: %zu bytes\n",membin.sUsed);

    /* 
     * Only free bin when everything is finished,because this code is an example,* it did not contain a reinitialize code.
     */
    freebin( &membin );
    /* membin size should be a value of after using freebin */
    printf("membin size after freed: %zu",membin.size);

    return 0;
}

您的情况很有趣,并且您的代码所产生的错误类型在各个编译器中都不相同。您的结构分配的问题是局部变量的地址,例如我在您的问题下方的评论。这可以通过全局变量来解决。但是,无法解决且不会在整个编译器中产生相同错误的是分配了指向内容字符的指针的地址。用全局变量无法解决这一问题。即使所有数据变为静态并具有自己的地址,某些编译器仍会显示错误,而某些则不会。我制作了下面的示例,该示例可以产生确切的错误,但更简单。

https://repl.it/languages/c上运行以下代码。运行超过10倍。有时,第一个test.c将变为空。另一方面,当我在Ubuntu的Linux的gcc版本7.4.0编译器上运行它时,test.c永远不会第二次显示正确的结果。

经验法则?不将指针分配给函数参数的地址吗?还是因为“指向chars的指针”具有本地地址?

#include <stdio.h>

typedef struct {
  char ** c;

} __test__;

__test__ test;

void fb (char * input );

void fa (char * input,int opt){
    if ( opt == 1 ) return;
    fb(input);
};

void fb ( char * input ){
    test.c = &input;
};

int main(void) {
    /* Test running this more than 10x and tell me what you think*/
    fa("Hello",0);
    printf("%s\n",*test.c);
    fa("This should not change c",1);
    fa("This should also not change c but for some reason sometimes c become null",1);
    printf("%s\n",*test.c);

    printf("\n\n");

    char * str = "Hello2"; 
    fa(str,1);
    fa("On some system c will show weird result on some this work perfectly fine. I guess the pointer\
        to the address of str get reset sometimes. Or is it the pointer to the parameter of fb getting reset? Or is it because the 'pointer to pointer' is a local address?",1);
    printf("%s",*test.c);
}
本文链接:https://www.f2er.com/3163497.html

大家都在问