You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言实现JSON解释器:递增pairsSize触发段错误崩溃

JSON解释器段错误问题排查与代码优化

我正在自行实现一款JSON解释器,但向结构体中添加值时,一旦递增pairsSize变量,程序就会因段错误崩溃。排查代码后发现,在case KEYPAIR_DELIM中取消json->pairsSize++的注释并执行内存重分配时,程序立即崩溃。相关代码如下:

json.c中interpret()函数部分代码

size_t jsonContentLen = strlen(jsonContent);
char * placeHolder = malloc(1);
unsigned int placeHolderPtr = 0;
bool isArray = false;

for (size_t i = 0; i < jsonContentLen; i++) {
    switch(jsonContent[i]) {
        case KEYPAIR_DELIM: {
            placeHolder[placeHolderPtr] = '\0';

            // 取消`json->pairsSize++`注释后立即触发段错误
            json->pairs = realloc(json->pairs, sizeof(struct Pair *) * (json->pairsSize+1));
            json->pairs[json->pairsSize] = init_pair();
            json->pairs[json->pairsSize]->key = realloc(json->pairs[json->pairsSize]->key, placeHolderPtr+1);
            strncpy(json->pairs[json->pairsSize]->key, placeHolder, placeHolderPtr+1);
            printf("%s\n", json->pairs[json->pairsSize]->key);

            placeHolder[0] = '\0';
            placeHolderPtr = 0;

        }
        case NEXT_PAIR: {
            placeHolder[placeHolderPtr] = '\0';
            size_t placeHolderLen = strlen(placeHolder);

            json->pairs[json->pairsSize]->values = realloc(json->pairs[json->pairsSize]->values, sizeof(void *) * (json->pairs[json->pairsSize]->valuesSize+1));

            // OMG THIS LOOKS SO BAD AHHHHHHH
            json->pairs[json->pairsSize]->values[json->pairs[json->pairsSize]->valuesSize] = malloc(placeHolderLen+1);
            
            strncpy(json->pairs[json->pairsSize]->values[json->pairs[json->pairsSize]->valuesSize], placeHolder, placeHolderLen+1);
            printf("%s\n", json->pairs[json->pairsSize]->values[json->pairs[json->pairsSize]->valuesSize]);

            placeHolder[0] = '\0';
            placeHolderPtr = 0;
            json->pairs[json->pairsSize]->valuesSize++;
            
            if (isArray == false) {

                // 莫名触发段错误,无法排查
                //json->pairsSize++;
            }
            break;
        }
    }
}

json.h部分代码

#define DOUBLE_QUOTE '"'
#define KEYPAIR_DELIM ':'
#define OBJECT_OPEN '{'
#define OBJECT_CLOSE '}'
#define ARRAY_OPEN '['
#define ARRAY_CLOSE ']'
#define NEXT_PAIR ','

struct Pair {
    char * key;
    void ** values;
    unsigned int valuesSize;
};

struct JSON {
    char * objectName;

    struct Pair ** pairs;
    unsigned int pairsSize;

    struct JSON ** objects;
    unsigned int objectsSize;
    struct JSON * prev;
};

struct JSON * init_json();
struct Pair * init_pair();

问题原因与修复

  1. 结构体初始化不完整

    • 确保init_json()中json->pairs初始化为NULL,json->pairsSize初始化为0;init_pair()中values初始化为NULL,valuesSize初始化为0。realloc对野指针操作会直接触发崩溃,未初始化的数组索引也会访问非法内存。
  2. case穿透导致越界访问

    • case KEYPAIR_DELIM代码块末尾缺少break,执行完该case后会直接进入case NEXT_PAIR逻辑。如果此时pairsSize已递增,访问json->pairs[json->pairsSize]->values会越界,直接触发段错误。修复后代码:
      case KEYPAIR_DELIM: {
          placeHolder[placeHolderPtr] = '\0';
          // 扩容并初始化新Pair
          json->pairs = realloc(json->pairs, sizeof(struct Pair *) * (json->pairsSize + 1));
          json->pairs[json->pairsSize] = init_pair();
          // 复制key值
          json->pairs[json->pairsSize]->key = realloc(json->pairs[json->pairsSize]->key, placeHolderPtr + 1);
          strncpy(json->pairs[json->pairsSize]->key, placeHolder, placeHolderPtr + 1);
          printf("%s\n", json->pairs[json->pairsSize]->key);
          // 最后递增计数
          json->pairsSize++;
      
          placeHolder[0] = '\0';
          placeHolderPtr = 0;
          break; // 新增break避免case穿透
      }
      
  3. placeHolder内存溢出

    • 初始placeHolder仅分配1字节空间,后续写入数据会越界破坏堆内存。改为动态扩容:
      // 替换原placeHolder初始化
      size_t placeHolderCap = 16;
      char * placeHolder = malloc(placeHolderCap);
      // 在每次写入placeHolder前检查空间
      if (placeHolderPtr >= placeHolderCap) {
          placeHolderCap *= 2;
          placeHolder = realloc(placeHolder, placeHolderCap);
      }
      placeHolder[placeHolderPtr++] = jsonContent[i];
      

代码可读性优化

使用临时指针减少多层嵌套的指针访问,简化代码:

// 在NEXT_PAIR的case中替换原有逻辑
struct Pair *currentPair = json->pairs[json->pairsSize - 1];
size_t newValuesSize = currentPair->valuesSize + 1;

currentPair->values = realloc(currentPair->values, sizeof(void *) * newValuesSize);
currentPair->values[currentPair->valuesSize] = malloc(placeHolderLen + 1);
strncpy(currentPair->values[currentPair->valuesSize], placeHolder, placeHolderLen + 1);
printf("%s\n", currentPair->values[currentPair->valuesSize]);

currentPair->valuesSize = newValuesSize;

内容的提问来源于stack exchange,提问作者ThatPrimitive_Remastered

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 23:25:25