问题描述
总而言之,如果函数被赋予参数 char *str1 = "当心街道?"; char *str2 = "street?";,它应该返回 str1 中的一个指针,指向 "street" 的第一个实例,从 s 开始。
我完全被困住了,感谢任何帮助。我有一种感觉,我的问题出在指针上。正如您想象的那样,我是一个初学者。
我刚刚将代码编辑为我最近的尝试。我很接近,但仍然找不到修改第一个字符串的想法。
输出图像:
const char *qstr_strstr(const char *str1,const char *str2) {
int j = 0;
char newstr2[256];
while (str2[j]) {
if (str2[j] == '?') {
break;
} else {
newstr2[j] = str2[j];
}
j++;
}
newstr2[j] = '\0';
size_t n = strlen(newstr2);
while(*str1) {
if (!memcmp(str1++,newstr2,n)) {
return (str1 - 1);
}
}
return NULL;
}
解决方法
您正朝着正确的方向前进,并且您开始考虑正确地逐步解决问题,但是您正忙于使用任何额外的字符串——没有必要这样做。
当您分析字符串和子字符串时,您只关心:
- 原始字符串中的索引(位置)(迭代);
- 你是否已经找到子串的开头(如果是的话,在单词匹配字符中设置标志);和
- 是否在设置标志的情况下一直到达子字符串的末尾(如果这样做,则说明您已找到子字符串)。否则,如果在到达结尾之前字符不匹配,请取消设置您的标志并继续。重复直到用完
str1
。
使您的情况复杂化的是 Red-Herring '?'
字符。您可以将其用作子字符串结尾的测试,也可以完全忽略它。您的目标是在 str2
"street"
内找到 str1
"... streets?"
。您通常会使用 ispunct()
中的 ctype.h
将 '?'
标识为非单词字符而不是字符串的一部分。在这里,您可以简单地检查 '?'
,就像检查 '\0'
以标记字符串结尾一样。
完全不使用任何 string.h
或 ctype.h
函数,您可以这样做:
#include <stdio.h>
const char *qstr_strstr (const char *str1,const char *str2)
{
int i = 0,instr2 = 0,ndx = 0; /* str1 index,in-str2 flag,str2 index */
if (str1 == NULL || str2 == NULL) /* validte both str1 and str2 not NULL */
return NULL;
do { /* loop over each char in str1 */
/* if in str2 and (at end or at '?') */
if (instr2 && (!str2[ndx] || str2[ndx] == '?'))
return &str1[i-ndx]; /* return address in str1 to start of str2 */
/* if char in str1 and str2 equal */
if (str1[i] == str2[ndx]) {
ndx += 1; /* increment str2 index */
instr2 = 1; /* set in-str2 flag true (done each time) */
}
else /* otherwise chars not equal */
ndx = instr2 = 0; /* reset str2 index,set in-str2 flag false */
} while (str1[i++]); /* includes \0,allows match at end of both */
return NULL;
}
int main (void) {
const char *str1 = "Watch of the streets?",*str2 = "street?",*ptr = qstr_strstr (str1,str2);
if (ptr) {
size_t i = ptr - str1;
printf ("ptr : %s\nptr addr : %p\n---\n"
"&str1[%zu] : %s\n&str1[%zu] : %p\n",ptr,(void*)ptr,i,str1 + i,(void*)(str1 + i));
}
}
示例使用/输出
输出由 qstr_strstr()
重新调整的字符串和加法器以及该字符串的地址和位于原始 str1
中的地址:
$ ./bin/strstrawk
ptr : streets?
ptr addr : 0x4006c1
---
&str1[13] : streets?
&str1[13] : 0x4006c1
您可以进一步仅从 street
中的地址复制子字符串 str1
或您需要执行的任何其他操作。仔细检查一下,如果您还有其他问题,请告诉我。
根据添加的图片进行编辑
如果您只想从 '?'
返回的指针中输出 qstr_strstr()
之前的字符,那么您可以通过使用带有 { 的 precision 修饰符轻松地做到这一点{1}} 在您的 "%s"
格式字符串中输出转换说明符,并将输出的字符数限制为 printf
中 '?'
之前的数字。您的格式转换说明符看起来像 str2
,它需要 2 个参数,第一个 "%.*s"
类型是字符数,第二个是字符串。
在上述情况下,参数为:
int
其中 (int)strcspn (str2,"?"),ptr
返回 strcspn()
中 '?'
之前的字符数(转换为 str2
)和 int
返回 ptr
.更改上面的代码,您将拥有:
qstr_strstr()
(其余代码不变)
...
#include <string.h>
...
printf ("ptr : %.*s\nptr addr : %p\n---\n"
"&str1[%zu] : %s\n&str1[%zu] : %p\n",(int)strcspn (str2,(void*)(str1 + i));
其中使用 $ ./bin/strstrawk
ptr : street
ptr addr : 0x4006c1
---
&str1[13] : streets?
&str1[13] : 0x4006c1
作为字符串且来自 ptr
的长度的输出不是 str2
。
如果您还有其他问题,请告诉我。