【问题标题】:C - Dynamic String Freeing and dynamic arrays [closed]C - 动态字符串释放和动态数组
【发布时间】:2016-01-08 19:06:01
【问题描述】:

我有一个与本学期的编程项目有关的问题。 我有一个具有结构的动态数组,该结构包含一个字符串的参数。问题是我需要将该字符串从静态更改为动态。 我已经编写了请求字符串并将其存储在动态数组中然后返回的函数。 稍后在程序中,我需要将数组(存储动态字符串)中的信息写入二进制文件。 我怎样才能做到这一点,我怎样才能知道何时以及如何正确释放该动态字符串的内存? 如果我释放了存储字符串的数组,我是否也释放了存储字符串本身的内存?

我的数组将存储字符串:

inspections *inspectionsArray;


char* dynamicString(){
    char *stringPointer = NULL,*paux = NULL, char;
    int stringSize = 1,stringEnd = 0,i;
    stringPointer = (char*)malloc(sizeof(char)); 
    if (stringPointer == NULL) {
        printf("\nError alocating memory");
    }else{
        printf("\nEnter String: ");
        while (char != EOF && char != '\n') {
            char = getc(stdin); //Obter o char do stding
            paux = realloc(stringPointer, stringSize*sizeof(char));
            if (paux != NULL) {
                stringPointer = paux;
                stringPointer[stringEnd] = char; //meter o char na string
                stringSize++; //incrementar o tamanho da string
                stringEnd++;
            }else{
                printf("\nErro a realocar memoria para a string");
            }
        }
        stringPointer[stringEnd] = '\0';
        printf("\nString: %s", stringPointer);
    }
    return stringPointer;
}

我将在其中存储字符串的结构。

typedef struct
{
    //A bunch of parameters in here
    char *dynamicString;

} inspection;


enter code here

我用来将数据存储到数组的函数:

inspectionArray* registerInspection(inspection *inspectionArray){
    char *string;
    //I removed a bunch of code to not confuse things
    string = dynamicString;

    return inspection;
}

文件保存功能:

void saveBinaryFile(inspection *inspections, int inspectionCounter)
{
    FILE * inspectionArrayFile;


    fileInspections = fopen("inspections.dat","wb"); 


    if (fileInspections == NULL)
    {
        perror("\nError opening the file");
    }
    else
    {
        fwrite(&inspectionCounter, sizeof (int), 1, inspectionArrayFile);
        fwrite(inspections, sizeof(tipoVeiculo), inspectionCounter, inspectionArrayFile);
        // I write a bunch of stuff and verify it properly
        fclose(inspectionArrayFile);

    }
}

如何正确读取和释放字符串?

我试过这个:

void freeArrayStrings(inspections *inspectionsArray,int counter){
    int i;
    for (i=0; i<counter; i++) {
        free(inspectionArray[i].dynamicString);
    }
}

【问题讨论】:

  • "说话很便宜。给我看代码 - Linus"
  • 没有动态数组。
  • 我有很多代码,我不能全部放在这里。那我试试
  • 你至少有两个完全独立的问题,一个是关于输出的,一个是关于内存管理的。在这里提出具体的问题,最好用代码来支持它们。
  • @LuisValdez 尝试创建minimal reproducible example

标签: c arrays string memory-management


【解决方案1】:

除非您出于某些特定原因为dynamicString() 函数使用面向字符的 输入,否则您可以通过使用一种面向行的 来大大简化您的工作标准 C 库提供的输入函数(例如 fgetsgetline)。此外,在 C 中,您通常会避免使用 camelCase 名称,而是使用 lower-case 来表示所有变量和函数名称。

dynamicstring() 函数的情况下,使用 getline 您的函数可简化为:

char *dynamicstring (inspection *i)
{
    char *line = NULL;  /* buffer for input                 */
    size_t n = 0;       /* alloc size 0 - getline decides   */
    ssize_t len = 0;    /* no. of character read (or EOF)   */

    printf("\nEnter String: ");

    len = getline (&line, &n, stdin);   /* read input   */

    if (len <= 1) {  /* line contains only '\n', 0, EOF */
        free (line);
        return NULL;
    }

    while (len > 0 && line[len-1] == '\n') /* remove '\n'  */
        line[--len] = 0;

    i->dstring = line;    /* assign pointer to dstring  */

    return line;
}

注意:上面我使用dstring作为您的char *dynamicString;成员)

您可以通过获取最终line 的长度,将内存分配大小从getline 分配的默认值细化为输入字符串所需的数量,分配该数量的内存(nul-terminator),并将line 复制到新的内存块中。您可以使用 strdup 函数一次性完成所有操作。例如,您可以在上面的函数中添加以下内容,然后返回str

    char *str = NULL;   /* pointer for final string storage */
    ...
    str = strdup (line);  /* refine allocation size     */
    free (line);

    i->dstring = str;     /* assign pointer to dstring  */

    return str;

即使经过细化,完成的功能也比原来的要简单得多。现在注意:无论您是否分配返回值,由于该函数仅在输入不为空时返回分配,所以您的一些inspection 字符串成员数组有可能是分配和一些空的。因此,您需要在释放内存之前进行检查。例如:

    if (ia->dstring)
        free (ia->dstring);

与往常一样,在动态分配内存时,请使用内存错误检查器(如 Linux 上的 valgrind)来确认您分配的内存的正确使用和释放。使用此输入函数的一个简短示例是:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char *dstring;
} inspection;

char* dynamicstring (inspection *i);

int main (void) {

    inspection *ia= NULL;

    if (!(ia= malloc (sizeof *ia))) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return 1;
    }

    if (dynamicstring (ia)) {
        printf ("\n inspectionArray->dynamicstring : %s\n\n", ia->dstring);
        if (ia->dstring)
            free (ia->dstring);
    }
    free (ia);

    return 0;
}

char *dynamicstring (inspection *i)
{
    char *str = NULL;   /* pointer for final string storage */
    char *line = NULL;  /* buffer for input                 */
    size_t n = 0;       /* alloc size 0 - getline decides   */
    ssize_t len = 0;    /* no. of character read (or EOF)   */

    printf("\nEnter String: ");

    len = getline (&line, &n, stdin);   /* read input   */

    if (len <= 1) {  /* line contains only '\n', 0, EOF */
        free (line);
        return NULL;
    }

    /* using shorthand 'len' instead of 'len > 0'
       both test false when 'len' is 0  */
    while (len && line[len-1] == '\n') /* remove '\n'  */
        line[--len] = 0;

    str = strdup (line);  /* refine allocation size     */
    free (line);

    i->dstring = str;     /* assign pointer to dstring  */

    return str;
}

试一试,如果您有任何问题,请告诉我。

【讨论】:

  • 谢谢大卫。就是这样!
  • 虽然你写的有些东西是用 C++ 写的。不是吗?
  • 不,所有这些都是 100% 纯 C ..... 哪些部分看起来像 C++?我很乐意解释您有任何疑问。了解每一行和每行中的每个字符很重要。没有像“close-enough”这样的语法...
  • 在 dynamicString 函数上,你使用了一段时间,但你没有使用任何括号。也许可以做到,我只是从未见过。非常感谢。
  • while (line &amp;&amp; line[len-1] == '\n') 确实需要改进才能正确。接得好。它应该是while (len &amp;&amp; line[len-1] == '\n'),它只是while (len &gt; 0 &amp;&amp; line[len-1] == '\n') 的简写。这虽然你没有一直向后工作到开头并且最后一个字符是'\n',然后用 nul-terminating 字符0 覆盖'\n'(相当于@ 987654345@) 但输入更少)并从len 中减去1 并再次检查。我会更新答案。
【解决方案2】:

您应该展示您的代码以增加获得恰当答案的机会。如果您询问如何释放存储指向另一个内存的指针的内存,请从 malloc 获取,如下例所示:

struct str_wrap
{
    char *str;
    int  strlen;
};

int main()
{
    struct str_wrap *sw = malloc(sizeof *sw);
    if (sw == NULL) return -1;

    sw->str = malloc(strlen);
    if (sw->str == NULL)
        // handle
    sw->strlen = strlen;
    // many things with sw...

那么是的,您必须拨打free 两次(注意:您拨打malloc 的次数相同):

    // free the memory
    free(sw->str);
    free(sw);
}

【讨论】:

    【解决方案3】:
    1. 你有一个错误:stringPointer = (char*)malloc(sizeof(char)); 你需要stringPointer = (char*)malloc(sizeof(char *)); sizeof(char) 可能是 1 个字节; sizeof(char *) 可能是 4。 您可能会侥幸成功,因为某些内存系统总是分配至少 32 个字节...

    2. 不要在每个输入字符上重新分配。相反,声明 char buf[255] 或其他最大大小,保留大小索引,将输入 char 分配到末尾,然后在最后执行 stringPointer = malloc(isize+1) 和 strcpy(stringPointer,buf);如果您确实可能需要一个巨大的输入缓冲区,请从 4K 或 1M 开始,然后在填充该空间时重新分配。

    【讨论】:

    • 那不会占用大量内存吗?
    • 否 - 我们的想法是在 getc 循环之外分配一个缓冲区。这将避免对处理的每个字符进行 realloc 调用(相对昂贵)。
    猜你喜欢
    • 2012-11-20
    • 1970-01-01
    • 1970-01-01
    • 2017-08-27
    • 1970-01-01
    • 2013-07-16
    • 2012-11-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多