6-4 查找子串

本题要求实现一个字符串查找的简单函数。

函数接口定义:

char *search( char *s, char *t );

函数search在字符串s中查找子串t,返回子串t在s中的首地址。若未找到,则返回NULL。

裁判测试程序样例:

#include <stdio.h>
#define MAXS 30

char *search(char *s, char *t);
void ReadString( char s[] ); /* 裁判提供,细节不表 */

int main()
{
    char s[MAXS], t[MAXS], *pos;

    ReadString(s);
    ReadString(t);
    pos = search(s, t);
    if ( pos != NULL )
        printf("%d\n", pos - s);
    else
        printf("-1\n");

    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例1:

The C Programming Language
ram

输出样例1:

10

输入样例2:

The C Programming Language
bored

输出样例2:

-1

 

char *search(char *s, char *t)
{
	char *ret = NULL;
	char *p,*q,*r;
	int flag = 0;
	while( *s != '\0'){
		p = s;
		q = t;
		r = s;    //记录首地址 
		while( *q != '\0'){
			if( *p == *q ){
				p++;
				q++;
			}else{
				break;
			}
		}
		if( *q == '\0'){
			flag = 1; 
			break;
		}
		s++;
	}
	if( flag )  ret = r;
	return ret;
}

 

<think>好的,我需要帮助用户了解在C语言中使用char*类型进行子串操作的方法,特别是查找子串函数。用户提到了strstr函数,并提供了几个引用,包括标准库的使用和自定义实现的例子。首先,我应该先确认用户的需求,他们可能想了解如何正确使用strstr函数,或者需要自己实现类似的功能,比如在面试或学习过程中。 用户提供的引用中有strstr的标准用法,比如引用[1]中的例子,使用strstr找到子串位置后替换内容。另外,引用[2]、[3]、[4]展示了如何自己实现strstr函数的不同方法。这说明用户可能对标准库函数和自定义实现都感兴趣,或者想比较两者的区别。 接下来,我需要整理这些信息,分点说明。首先介绍标准库的strstr函数,包括函数原型、参数、返回值以及使用示例。然后,针对用户可能需要的自定义实现,分析不同实现方法的思路,比如暴力匹配、KMP算法等,并给出代码示例。同时,需要指出注意事项,比如内存安全、性能问题,以及如何处理空指针等情况。 用户的问题中提到“char*类型进行子串操作”,除了查找,可能还涉及子串的提取或修改,但当前引用主要集中在查找,所以应重点回答查找方法。需要确保回答结构清晰,先讲标准库函数,再讲自定义实现,最后注意事项和常见问题。 还需要考虑用户可能的后续问题,比如如何优化子串查找,或者处理多次出现的情况,但根据用户当前的问题,集中在查找方法上,所以主要覆盖这些点。同时,根据用户提供的引用,引用[2]、[3]、[4]中的自定义实现各有不同,需要指出它们的异同,比如引用[3]使用了assert和指针操作,引用[4]提到了记录起始位置以处理多次匹配的情况。 最后,生成的相关问题需要围绕用户可能感兴趣的扩展,比如与strncpy的配合使用,不同查找算法的效率比较,或者如何处理大小写敏感问题。确保回答准确引用提供的资料,并符合C语言的标准做法。</think>### C语言中`char*`类型子串查找方法详解 在C语言中,使用`char*`类型进行子串操作主要依赖字符串处理函数`strstr()`,也可通过自定义函数实现。以下是具体方法与关键细节: --- #### 一、标准库函数`strstr()` ##### 1. 函数原型 ```c char* strstr(const char* haystack, const char* needle); ``` - **功能**:在字符串`haystack`中查找子串`needle`首次出现的位置 - **返回值**- 找到子串:返回指向首次匹配位置的指针 - 未找到子串:返回`NULL` - **头文件**:`#include <string.h>` ##### 2. 基础用法示例 ```c #include <stdio.h> #include <string.h> int main() { char str[] = "Programming in C is efficient"; char* substr = strstr(str, "C"); // 查找"C"的位置 if (substr != NULL) { printf("找到子串,位置:%ld\n", substr - str); // 输出偏移量 printf("从子串开始的内容:%s\n", substr); // 输出:"C is efficient" } else { printf("未找到子串\n"); } return 0; } ``` ##### 3. 典型应用场景 - **字符串截取**:结合指针偏移获取子串后续内容 ```c char path[] = "/home/user/docs/file.txt"; char* filename = strstr(path, "file"); // 直接定位文件名起始位置 ``` - **内容替换**:配合`strncpy()`修改特定子串(如引用[1]的示例) ```c char text[] = "This is a simple string"; char* pos = strstr(text, "simple"); if (pos) strncpy(pos, "sample", 6); // 替换为"sample" ``` --- #### 二、自定义子串查找函数 当需要特定功能(如统计所有匹配位置)或学习底层实现时,可手动实现子串查找逻辑。以下是两种常见实现方式: ##### 1. 暴力匹配法 **核心逻辑**:逐字符比较主串与子串,时间复杂度$O(n \times m)$ (参考引用[2][3][4]的实现思路) ```c #include <assert.h> char* my_strstr(const char* haystack, const char* needle) { assert(haystack && needle); if (*needle == '\0') return (char*)haystack; // 处理空子串 for (const char* p = haystack; *p; p++) { const char* h = p; const char* n = needle; while (*h && *n && (*h == *n)) { h++; n++; } if (*n == '\0') return (char*)p; // 完全匹配 } return NULL; } ``` ##### 2. KMP算法优化 **核心逻辑**:通过前缀表跳过无效匹配,时间复杂度$O(n + m)$ (适合处理大规模文本) ```c // 生成部分匹配表 void computeLPS(const char* needle, int* lps) { int len = 0; lps[0] = 0; for (int i = 1; needle[i]; ) { if (needle[i] == needle[len]) { lps[i++] = ++len; } else { if (len != 0) len = lps[len-1]; else lps[i++] = 0; } } } char* kmp_strstr(const char* haystack, const char* needle) { int n = strlen(haystack), m = strlen(needle); if (m == 0) return (char*)haystack; int lps[m]; computeLPS(needle, lps); int i = 0, j = 0; while (i < n) { if (haystack[i] == needle[j]) { i++; j++; if (j == m) return (char*)(haystack + i - j); } else { if (j > 0) j = lps[j-1]; else i++; } } return NULL; } ``` --- #### 三、关键注意事项 1. **安全性**- 标准库`strstr()`不检查空指针,需自行验证参数有效性[^1] - 自定义实现时使用`assert()`防御性编程(如引用[3]) 2. **性能对比**- `strstr()`通常经过编译器优化,效率高于普通暴力匹配 - 高频操作或大文本优先使用KMP等优化算法[^2] 3. **内存管理**- 返回的指针指向原字符串**不可直接修改**(若原字符串为常量) - 需复制到新内存后再修改(参考引用[1]的`strncpy`用法) --- #### 四、综合应用示例 ```c #include <stdio.h> #include <string.h> int main() { char log[] = "[ERROR] File not found: /data/config.json"; // 使用标准库定位错误类型 char* errorType = strstr(log, "[ERROR]"); if (errorType) { printf("错误类型:%s\n", errorType); // 输出完整错误信息 // 提取文件名 char* filename = strstr(log, "File not found: "); if (filename) { filename += strlen("File not found: "); printf("缺失文件:%s\n", filename); // 输出:/data/config.json } } return 0; } ``` --- ### 相关问题 1. 如何统计子串字符串中的所有出现位置? 2. `strstr()`与`memmem()`函数在二进制数据查找中的区别? 3. 如何实现不区分大小写的子串查找4. 为什么KMP算法比暴力匹配更适合处理重复模式?[^3] [^1]: 引用自用户提供的C语言`strstr()`示例代码 [^2]: 参考用户提供的自定义`MyStrstr()`实现逻辑 [^3]: 基于KMP算法优化思路的扩展分析
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值