C语言新手如何处理SPOJ题目中的SIGSEGV(段错误)?
解决SPOJ标识符统计任务中的SIGSEGV段错误问题
任务回顾
要求编写C语言程序统计每行中符合规则的标识符数量:
- 标识符定义:由
a-z、A-Z、0-9或_组成,且必须以字母或_开头 - 输入:多行文本,每行包含空格分隔的单词(单词为ASCII 33-126的字符序列)
- 输出:每行对应的标识符数量
示例输入
Dato25 has 2 c-ats and 3 _dogs op8ax _yu _yu67 great-job ax~no identifier.
示例输出
4 3
SIGSEGV段错误的常见排查方向及解决方法
代码能编译但触发段错误,通常是内存访问违规导致的,结合这个任务场景,重点检查以下几点:
1. 数组越界访问
如果用固定大小的数组存储输入行,当输入行长度超过数组容量时,会写入到数组外的内存区域,触发段错误。
- 解决:使用动态内存分配的方式读取行,比如标准库的
getline函数(自动分配/扩容缓冲区),或者手动用malloc+realloc处理长行。
2. 空指针解引用
处理字符串时未检查指针是否为NULL就直接操作,比如:
strtok返回NULL后仍继续访问其内容malloc/calloc分配内存失败后未判断,直接使用指针- 解决:所有指针操作前必须做非空校验,比如
strtok循环时要判断返回值是否为NULL;内存分配后检查if (ptr == NULL)并处理错误。
3. 字符串操作函数的错误使用
比如用strcpy/strcat时目标缓冲区不足,或者strtok跨多行处理时未正确重置状态:
- 解决:优先用
strncpy(注意手动添加字符串终止符'\0'),或用getline读取整行后再分割;每行处理时,strtok第一次调用传入行字符串,后续调用传入NULL,确保每行独立处理。
4. 单词处理的边界错误
比如未判断单词是否为空就直接访问word[0],或者遍历单词字符时超出字符串长度:
- 解决:处理每个单词前先判断是否为空字符串;遍历字符时以
'\0'为终止标志,或用strlen获取长度后控制遍历范围。
参考代码示例
以下是符合要求且能避免常见段错误的实现:
#include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> // 判断单个单词是否为合法标识符 int is_identifier(const char *word) { if (word == NULL || *word == '\0') { return 0; } // 检查首字符:必须是字母或下划线 if (!isalpha((unsigned char)*word) && *word != '_') { return 0; } // 检查后续所有字符 while (*++word != '\0') { if (!isalnum((unsigned char)*word) && *word != '_') { return 0; } } return 1; } int main() { char *line = NULL; size_t buf_size = 0; ssize_t read_len; // 逐行读取输入 while ((read_len = getline(&line, &buf_size, stdin)) != -1) { // 去除换行符(如果存在) if (read_len > 0 && line[read_len - 1] == '\n') { line[read_len - 1] = '\0'; } int count = 0; char *token = strtok(line, " "); // 分割每行的单词并统计 while (token != NULL) { if (is_identifier(token)) { count++; } token = strtok(NULL, " "); } printf("%d\n", count); } // 释放getline分配的内存 free(line); return 0; }
代码关键点说明
- 使用
getline动态读取行,避免固定数组的越界问题 is_identifier函数先做空值校验,再严格按规则验证每个字符strtok正确处理每行的单词分割,确保每行独立计算- 最后释放动态分配的内存,避免内存泄漏
内容的提问来源于stack exchange,提问作者andromedstrain
相关产品推荐
相关产品推荐

