【问题标题】:Calling a function too many times in a while loop在while循环中多次调用函数
【发布时间】:2023-03-19 08:06:01
【问题描述】:

函数char** read(char file[])应该返回一个字符串数组,每个字符串代表一个从json文件中提取的Json对象。

char* Purge(char S[], int n) 从字符串(从 json 文件中提取)中删除 ' '(空格)、'"'',''\t'

主要问题是while循环中的第一条语句seBuffer = Purge(Buffer, strlen(Buffer) + 1);它使用Purge函数的方式太多次,对于已经检查过的字符,它从头到尾一直发生一个 json 对象,这是我应该担心的事情吗?还是有其他可能更有效的方法?

char** read(char file[])
{
    FILE* pF = fopen(file, "r");

    if(pF == NULL)
    {
        exit(EXIT_FAILURE);
    }

    char Buffer[MAX], oJson[MAX], c;
    char* seBuffer;
    int nbOJ = 0, toAllocate = 0;
    
    while((c = fgetc(pF)) != EOF)
        if(c == '{')
            nbOJ++;
    
    Size = nbOJ;

    rewind(pF);

    char** ObjectsJson = (char**)malloc(nbOJ*sizeof(char*));
    nbOJ = -1;

    while(fgets(Buffer, MAX, pF))
    {
        seBuffer = Purge(Buffer, strlen(Buffer) + 1);

        if(seBuffer[0] == '[' || seBuffer[0] == ']')
            continue;

        if(seBuffer[0] == '{')
        {
            oJson[0] = 0;
            nbOJ++;
            continue;
        }
        
        if(seBuffer[0] == '}')
        {
            ObjectsJson[nbOJ] = (char*)malloc((toAllocate+1)*sizeof(char));

            strcpy(ObjectsJson[nbOJ], oJson);
            toAllocate = 0;

            continue;
        }
        
        toAllocate += strlen(seBuffer);
        sprintf(oJson, "%s%s", oJson, seBuffer);
    }
    free(seBuffer);
    fclose(pF);
    return ObjectsJson;
}

【问题讨论】:

  • 这个问题令人困惑。所以你对代码进行了基准测试,函数调用是程序中最慢的部分?
  • 如果代码已经生效,您也可以在Code Review 上提问(提问前请阅读帮助中心)
  • 如果 Purge每个 调用中执行malloc,你就是泄漏 内存。那是因为您只在循环结束后执行 single free(seBuffer) after 。您需要在 each 循环迭代中执行一次,对应于来自Purge 的每个分配
  • (顺便说一句,你没有包含minimal reproducible examplePurge 函数是从哪里来的?)
  • @BeyondCrisp 我不明白你的意思。每次通过循环 fgets 从文件中读取一行。 Purge 采用这一行并完成它的工作。 Purge 在任何时候都不会处理它从之前的循环迭代中处理过的东西,因为每次调用它时,文件中都会有一个新行。那么它怎么能检查它之前检查的东西呢?

标签: c string function loops


【解决方案1】:

这是由顶级 cmets re 开头的。就地修改和内存泄漏。

因为Purge 只删除了一些字符,所以它可以就地执行此操作。所以,根本不需要strlenmalloc。见下文...


您的Purge 代码存在一些问题。

在下面的原始代码中,Purge 的调用者执行 strlen 并将其作为第二个参数传递。 Purge 然后执行它自己的strlen,覆盖/丢弃调用者的值。

Purge 预扫描输入字符串一次以获得要删除的字符数/计数。

这样可以减少给予malloc 的金额。但是,对于这个用例,只使用原始长度会更好,因为它节省了额外的扫描,这在很大程度上是一个很好的选择。

但是,如果我们真的想在缩短列表上使用malloc,并进行预扫描,预扫描循环可以计算要省略的字符数字符串长度一次通过。因此,所有单独的 strlen 调用都是多余的。

所以,在原始代码中,字符串缓冲区一共被扫描了四次次。


这是您的 Purge 函数的原始代码:

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

char *
Purge(char S[], int n)
{
    // ETVG = Espace , tabulation, virgule, guillemet
    int nbETVG = 0, j = 0;

    n = strlen(S);

    for (int i = 0; i < n; i++)
        if (S[i] == ' ' || S[i] == '\t' || S[i] == ',' || S[i] == '"')
            nbETVG++;

    int m = n - nbETVG;
    char *SE = (char *) malloc(m * sizeof(char));

    for (int i = 0; i < n; i++) {
        if (S[i] == ' ' || S[i] == '\t' || S[i] == ',' || S[i] == '"')
            continue;

        SE[j] = S[i];
        j++;
    }

    return SE;
}

void
main()
{
    char *Pstr;
    char str[] = { "this , is a       test  ." };
    Pstr = Purge(str, strlen(str));
    printf("%s", Pstr);
}

这里是重构的Purge代码:

#include <stdio.h>

void
Purge(char *src)
{
    char *dst = src;

    for (int chr = *src++;  chr != 0;  chr = *src++) {
        switch (chr) {
        case ' ':
        case '\t':
        case ',':
        case '"':
            break;
        default:
            *dst++ = chr;
            break;
        }
    }

    *dst = 0;
}

int
main(void)
{
    char str[] = { "this , is a       test  ." };

    printf("%s\n", str);
    Purge(str);
    printf("%s\n", str);

    return 0;
}

【讨论】:

    猜你喜欢
    • 2015-07-13
    • 2015-07-26
    • 1970-01-01
    • 1970-01-01
    • 2018-03-15
    • 1970-01-01
    • 2017-11-24
    • 1970-01-01
    • 2019-04-26
    相关资源
    最近更新 更多