将指针移至数组起始位置前是否存在问题?C语言代码疑问及改写需求
strend函数指针越界问题与改写方案
指针移动到数组起始位置之前的风险
将指针移动到数组起始位置之前是未定义行为。根据C语言标准,指向数组元素的指针仅能合法指向:
- 数组的某个元素
- 数组尾元素的下一个位置(尾后指针)
一旦指针越过数组首元素向前,就处于无效状态。此时对这类指针进行比较(如se >= s)或后续操作,结果不可预测,不同编译器可能有不同表现,甚至触发程序崩溃。
原代码的问题分析
- 指针越界的未定义行为:原代码中,当
se减到s的前一个位置、te减到t的前一个位置时,se >= s和te >= t的比较属于未定义行为,因为此时指针已超出合法范围。 - 空字符串的潜在问题:若
t是空字符串,te初始等于t,进入循环后te--会直接跳到t-1,后续指针操作完全违反标准。 - 关于“指针初始化为0导致下溢”:正常情况下,字符串指针不会指向地址0(NULL除外),若传入NULL,
while(*te)会直接解引用空指针导致崩溃。即便极端情况t指向地址0,te--会生成非法地址,这属于指针非法访问,而非数值下溢,但同样是严重的未定义行为。
改写后的代码(避免指针越界)
我们可以先计算两个字符串的长度,确保从后往前比较时不会越过数组起始位置,以下是两种可靠实现:
实现方式1:先定位比较起始位置
#include <stdio.h> int strend(char *s, char *t); int main() { char a[] = "hello world"; char b[] = "orld"; int i = strend(a, b); printf("%d", i); return 0; } int strend(char *s, char *t) { // 空字符串默认匹配所有字符串结尾 if (*t == '\0') { return 1; } // 计算s的长度 char *s_ptr = s; size_t len_s = 0; while (*s_ptr++) { len_s++; } // 计算t的长度 char *t_ptr = t; size_t len_t = 0; while (*t_ptr++) { len_t++; } // t比s长,直接不匹配 if (len_t > len_s) { return 0; } // 将s移动到待比较的起始位置 s_ptr = s + len_s - len_t; t_ptr = t; // 逐字符比较 while (*t_ptr) { if (*s_ptr != *t_ptr) { return 0; } s_ptr++; t_ptr++; } return 1; }
实现方式2:从后往前限定比较次数
#include <stdio.h> #include <stddef.h> // 用于ptrdiff_t类型 int strend(char *s, char *t); int main() { char a[] = "hello world"; char b[] = "orld"; int i = strend(a, b); printf("%d", i); return 0; } int strend(char *s, char *t) { char *s_end = s; char *t_end = t; // 定位到字符串末尾的'\0' while (*s_end) s_end++; while (*t_end) t_end++; // 计算t的长度 ptrdiff_t t_len = t_end - t; // s的长度小于t,直接返回0 if ((s_end - s) < t_len) { return 0; } // 从后往前比较t_len个字符,不会越界 while (t_len-- > 0) { if (*(--s_end) != *(--t_end)) { return 0; } } return 1; }
这两种实现都严格遵循C标准,避免了指针越界的未定义行为,同时正确处理了空字符串等边界情况。
内容的提问来源于stack exchange,提问作者Gary Ong
相关产品推荐
相关产品推荐

