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

C语言结构体成员值异常:调用无关函数后pin值遭破坏

问题:调用parse_string后结构体中pin数组值被异常覆盖

本人刚接触C语言,自认对部分知识有所了解,但对细节掌握不足。以下是从复杂程序中提取的最小可复现示例(MWE),代码可正常编译运行,但测试发现:ev->pin初始值正确,调用parse_string函数后值却异常,疑似内存被覆盖,但无法定位原因。

复现代码

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

#define SCAN_EVENT_COUNT 5
#define PIN_ASSIGNMENTS {7, -1, 1, 13, 4}
#define EVENT_NAMES "first-second-third-fourth-fifth"

void init_scan_events();
int parse_string(char pInputString[],
                 char *Delimiter,
                 char *pToken[]);

struct scan_events
{
  char event_names[31];
  char *pEvent[SCAN_EVENT_COUNT];
  int pin[SCAN_EVENT_COUNT];
};

int main(void)
{
  init_scan_events();
  return (0);
}

/**
 * Note that `strtok` expects a `char * string` and `char * delimiter` as arguments.
 **/

int parse_string(char pInputString[],
                 char *Delimiter,
                 char *pToken[])
{
  int i = 0;
  pToken[i] = strtok(pInputString, Delimiter); // get first token
  i++;
  while ((pToken[i] = strtok(NULL, Delimiter)) != NULL) // get the rest of the tokens
  {
    i++;
  }
  return i;
}

void init_scan_events()
{
  char en[] = EVENT_NAMES;
  int en_size = strlen(en);
  int size = SCAN_EVENT_COUNT;
  int pin[] = PIN_ASSIGNMENTS;

  int token_count = 0;
  char *Delim = "-";
  int i;

  struct scan_events *ev = malloc(sizeof(struct scan_events));
  if (ev == NULL)
  {
    printf("Allocation failed\n");
  }

  for (int i = 0; i < en_size; i++) // copy EVENT_NAMES
  {
    ev->event_names[i] = en[i];
  }

  for (int i = 0; i < size; i++) // copy PIN_ASSIGNMENTS
  {
    ev->pin[i] = pin[i];
  }

  for (int i = 0; i < size; i++)
  {
    printf("% d ", ev->pin[i]); // inspect pin values: correct!
  }
  printf("\n");

  token_count = parse_string(ev->event_names, Delim, ev->pEvent); // tokenize EVENT_NAMES

  for (int i = 0; i < size; i++)
  {
    printf("% d ", ev->pin[i]); // check pin values: corrupted!
  }
  printf("\n");

  free(ev);
}

问题原因

核心问题是**ev->event_names字符串未以空字符\0结尾**,导致strtok越界破坏内存:

  • 循环复制en内容时,只复制了strlen(en)个字符,漏掉了字符串必须的结束符\0
  • strtok会持续扫描直到遇到\0,由于event_names没有结束符,它会继续访问结构体中event_names之后的内存(即pEvent数组和pin数组的空间),在将分隔符替换为\0的过程中,直接改写了pin数组的内容,造成值异常

修复方案

方案1:补全字符串结束符

修改复制event_names的循环,把结束符也复制进去:

for (int i = 0; i <= en_size; i++) // 用<=包含最后的'\0'
{
  ev->event_names[i] = en[i];
}

或者更简洁地用strcpy(event_names数组大小足够容纳目标字符串):

strcpy(ev->event_names, en);

方案2:用calloc初始化内存

用calloc代替malloc分配内存,它会自动将所有内存初始化为0,这样即使忘记复制结束符,event_names末尾也会有默认的\0:

struct scan_events *ev = calloc(1, sizeof(struct scan_events));

额外优化:限制token数量避免越界

当前parse_string没有限制最大token数,如果输入字符串分割出的token超过SCAN_EVENT_COUNT,会导致pEvent数组越界。可以给函数添加最大token数参数:

int parse_string(char pInputString[], char *Delimiter, char *pToken[], int max_tokens)
{
  int i = 0;
  if (max_tokens == 0) return 0;
  pToken[i] = strtok(pInputString, Delimiter);
  if (pToken[i] == NULL) return 0;
  i++;
  while (i < max_tokens && (pToken[i] = strtok(NULL, Delimiter)) != NULL)
  {
    i++;
  }
  return i;
}

调用时传入SCAN_EVENT_COUNT:

token_count = parse_string(ev->event_names, Delim, ev->pEvent, SCAN_EVENT_COUNT);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 18:24:59