关于C++代码中strstr指针运算及提取最后子串的疑问
字符串处理代码疑问解析
我无法理解这段代码的工作原理,尤其是
i=strstr(s + k, t) - s;这一行。我知道strstr()会返回指针,而这段代码的功能是提取字符串中最后出现的子串,但为何指针减去字符串会得到无符号类型的最后出现位置?我尝试将数据类型改为unsigned或int,调换s的位置(如s - strstr(...)),代码便无法运行。输入示例:
ana si mariana canta la nai和na,输出示例:ana si mariana canta la i代码如下:
#include <iostream> #include <cstring> using namespace std; char s[256], t[256]; int main() { unsigned i, n, k = 0, x = 0; gets(s); gets(t); n = strlen(t); while(k < strlen(s) && x < strlen(s)) { i = strstr(s + k, t) - s; k = i + n; x = strstr(s + k, t) - s; } strcpy(s + i, s + i + n); cout << s; return 0; }
核心逻辑与疑问拆解
这段代码的实际作用是删除字符串s中最后一次出现的子串t,以下针对你的疑问逐一解释:
1. i = strstr(s + k, t) - s; 的本质
strstr(a, b)会在字符串a中查找子串b,返回第一个匹配位置的指针,找不到则返回NULL。s + k是指针偏移:数组名s本质是指向字符串首字符的指针,s + k就是从s的第k个字符开始的子串起始地址。- 同类型指针相减的规则:两个指向同一内存块的同类型指针相减,结果是它们之间的元素个数。
strstr返回的指针指向s内部的某个字符,减去s(首字符指针),得到的就是该位置距离首字符的偏移量——也就是子串t在s中的起始下标。
2. 为什么调换指针位置会失效?
指针减法有严格要求:只有高地址指针减去低地址指针时,结果才是合法的正下标。如果写成s - strstr(...),相当于用低地址指针减高地址指针,结果会是负数。而i是unsigned类型,负数会被强制转换成超大的无符号数,直接破坏循环逻辑,代码自然无法运行。
3. 关于数据类型的问题
- 原代码用
unsigned存下标是合理的:字符串下标不可能为负,无符号类型能避免负数干扰。但改成int也能正常工作(前提是子串t存在于s中);如果strstr返回NULL(找不到子串),NULL - s会得到负数,赋值给int会保留负数,赋值给unsigned会变成大正数,都会导致后续逻辑崩溃——原代码能运行是因为输入保证了子串存在。 - 循环的逻辑是不断向后查找下一个子串:每次找到
k位置之后的第一个t,记录下标i,然后把k移到i + n(跳过当前找到的t),再查下一个t的位置x。当x超出字符串长度(找不到下一个t),循环停止,此时i就是最后一次出现t的下标,最后用strcpy把i + n开始的内容覆盖到i位置,相当于删除了这个t。
4. 代码的潜在问题
gets函数已被C标准废弃,存在缓冲区溢出风险,建议用fgets替代。- 未处理
strstr返回NULL的情况(比如t不在s中),此时i = NULL - s会生成非法值,直接导致程序崩溃。
内容的提问来源于stack exchange,提问作者nex
相关产品推荐
相关产品推荐

