C 语言题目,造轮子,看谁的轮子最厉害,有牛奶奖励。

2017-06-22 03:14:00 +08:00
 NullMan

题目:

从字符串删除特定子字符串。

条件

这题目是从“ C 和 指针”这书看到的,条件三是我自己添加的。

函数原型:

void del_substr(char *str, const char *substr);

举例:

char str[] = "ABCDEFG";
char substr[] = "CDE";
del_substr(str, substr);

这个时候,str 的值就应该是"ABFG"。
如果 substr 为 “ CDG ”, 执行该函数,str 保持不变("ABCDEFG")

实现:

以下代码乃本人所写,虽然刚学 C, 但是仍然对此代码不满意,代码行数太多了,太绕了,不直接。直觉告诉我,还可以写得更精简。望各位赐教一下,多谢!

void del_substr(char *str, const char *substr) {
    int i = 0, j = 0;
    while (*(str+i)) {
        j = 0;
        while (*(substr+j) && *(substr+j) == *(str+i+j)) {
            j++;
        }
        if (! *(substr+j)) {
            break;
        }
        else {
            i++;
        }
    }
    if (! *(substr+j)) {
        while ((*(str+i) = *(str+i+j))) {
            i++;
        }
    }
}

奖励:

代码写得最简单,最精炼, 我请你喝牛奶。:)

4820 次点击
所在节点    C
46 条回复
bp0
2017-06-22 09:36:25 +08:00
循环找到子串的起始和结束位置,

找到起始和结束位置,则复制结束位置后面剩余的字符串即可。

如果没有剩余字符,直接在起始位置置 0。
bp0
2017-06-22 10:10:18 +08:00
'''c
void del_substr(char *str, const char *substr)
{
char *end;
const char *rawsub;

if (!str || !substr || !*substr)
return ;

end = str;
rawsub = substr;
while (*str) {
if (!*substr) {
while ( *str++ = *end++);
} else if (*str == *substr) {
end++;
substr++;
} else {
end = ++str;
substr = rawsub;
}
}
}

'''

没经过测试,楼主有兴趣可以测试一下。

另外,这个代码只能删除第一个符合要求的字串。如果要删除所有字串还需要再调整一下 while 中第一个 if 的内容。
ryd994
2017-06-22 10:15:01 +08:00
不能使用数组下标这个要求说明出题的根本不懂 C
C 标准规定了 arr[i] 和 *(arr+i) 必须完全等效
bp0
2017-06-22 10:22:08 +08:00
@ryd994 问题的特殊性导致,不用下标也是可以完成题目要求的。这和 are[i]和*(arr+i)是不是等效没有关系。楼主用*(arr+i),本质上就是用下标。
misaka20038numbe
2017-06-22 10:37:11 +08:00
@bp0 经过测试,楼主和 11 楼的可以,你的不行.执行完后还是 ABCDEFG
besto
2017-06-22 10:39:33 +08:00
既然看了 C 和指针,那就应该看看 C 专家编程,你的要求最后一点压根不是事情(既可以考虑位段来做,也可以考虑用位移来做,压缩变量呗)

另外同意楼上。不然还可以写 i[arr]也完全等效。。。
coderluan
2017-06-22 11:49:26 +08:00
严格说这个不是轮子吧,OJ 题而已,还是水题,要比也得比执行速度啊啊,想代码简单别用 C 多好。

PS:喝牛奶是啥?
bp0
2017-06-22 11:51:12 +08:00
@misaka20038numbe 谢谢帮忙测试,更新了一下代码。这次应该没有问题了。


```c

void del_substr(char *str, const char *substr)
{
char *end;
const char *rawsub;

if (!str || !substr || !*substr)
return ;

end = str;
rawsub = substr;
while (*str) {
if (!*substr) {
while ((*str++ = *end++));
break;
} else if (*end == *substr) {
end++;
substr++;
} else {
end = ++str;
substr = rawsub;
}
}
}

```
yangff
2017-06-22 11:55:41 +08:00
@livid 为什么我在这个帖子的回复没有出现在我自己的回复列表里。。?

这个帖子有啥特殊的吗
bp0
2017-06-22 12:41:58 +08:00
@yangff 确实没有,貌似应该是 @Livid
araraloren
2017-06-22 15:03:23 +08:00
@yangff 有时候别人 AT 我一样没有提示。。
deeporist
2017-06-22 15:45:57 +08:00
嗯 之前学 scheme 时遇到过这种题目 等自己用 C 写起来才发现 难怪说 lisp 是专门针对 list 的了 一个 cdr 就能搞定这之后的千千万 c 的话还得自己往后一个一个接回去 痛苦
```
# include <stdio.h>
char str[]="ABCDEFG";
char substr[]="CDE";
void del_substr(char *,char *);
int i,j;
int main()
{
i=(int)sizeof(str);
j=(int)sizeof(substr);
del_substr(str,substr);
printf("%s",str);
return 0;
}

void del_substr(char *ori,char *tar)
{
if(j==1)
{
j=((int)sizeof(substr))-1;
while((i--)>1)
{*(ori-j)=*(ori);ori++;}
*(ori-j)='\0';
j=1;
}

if((*ori)==(*tar))
{
i--;j--;
del_substr(ori+1,tar+1);
}

if(--i>1)
del_substr(ori+1,tar);

}

```

两个变量 i j 纯粹当作计数器 sizeof 算是操作符 主要以递归形式循环

md 就这辣鸡问题我居然还从上午折腾到现在 菜得让自己吃惊
cnfreesw
2017-06-22 15:46:12 +08:00
牛奶,桶装还是试管装?
yangff
2017-06-22 16:27:25 +08:00
感觉第二种写法还是比较有潜力的
https://gist.github.com/Yangff/f9944276a72acb3808968a2b64139db0
最终版(大概)
ShiHou
2017-06-22 17:03:27 +08:00
吐槽下.. 这题写短的精髓应该是仅用一层循环而不是死命缩变量名
JohnSmith
2017-06-22 17:13:16 +08:00
效率最高的是 kmp 算法
yangff
2017-06-22 17:27:25 +08:00
@ShiHou 既然你这么说的话… PlanB 的压行版(虽然我觉得这种压法还不如写两行…)

for (int i = 0, j = 0; *str = *(str+i); (*(str+i+j) == *(substr+j) && *(substr+j)) ? (j++) : (i += !*(substr+j) * j, str += !!*(substr+j), j = 0));
lzhCoooder
2017-06-22 18:04:36 +08:00
你这么搞基本没意义,想造轮子就写个“看毛片”吧
headmaster
2017-06-22 18:23:32 +08:00
@JohnSmith KMP 没有 BM 效率高吧
NullMan
2017-06-22 18:28:31 +08:00
@yangff #34 卧槽!你这写法老牛逼了,我的只能删除第一个子字符串,你这是全都能删除!就是你了!留下收款账号,给你红包请你喝盒装牛奶,我比较穷,请不起咖啡:)

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/370191

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX