2014-01-08 268 views
0

尝试写入“单词”中的每个字母出现在“s”中时返回1的函数。 例如: 指向字符串C的指针

containsLetters1( “this_is_a_long_string”, “气体”)返回1

containsLetters1( “this_is_a_longstring”, “暖气”)返回0

containsLetters1( “你好”, “p”)返回0

不能明白为什么它不正确的:

#include <stdio.h> 
#include <string.h> 
#define MAX_STRING 100 

int containsLetters1(char *s, char *word) 
{ 
int j,i, flag; 
long len; 
len=strlen(word); 

for (i=0; i<=len; i++) { 
    flag=0; 
    for (j=0; j<MAX_STRING; j++) { 
     if (word==s) { 
      flag=1; 
      word++; 
      s++; 
      break; 
     } 
     s++; 

    } 
    if (flag==0) { 
     break; 
    } 
} 
return flag; 
} 

int main() { 
    char string1[MAX_STRING] , string2[MAX_STRING] ; 

printf("Enter 2 strings for containsLetters1\n"); 

scanf ("%s %s", string1, string2); 

printf("Return value from containsLetters1 is: %d\n",containsLetters1(string1,string2)); 

return 0; 
+0

你的'scanf'调用是不安全的 - 我可以输入更长的字符串,并且打碎你的堆栈 – Nazar554

+0

内部循环应该超过's'的有效长度,而不是MAX_STRING。你也失去了's'(和'word')的原始值,所以你不能再从头开始匹配'word'中的第二个字符。 –

+0

您正在比较指针,而不是它们指向开始的值。没有正确验证字符串长度时会出现更多错误,当遇到不匹配时会将指针向后重置,等等。 – EkriirkE

回答

2

尝试这些:

  1. for (i=0; i < len; i++)...(使用<而不是< =,否则你会采取一个额外的字符);
  2. if (word==s)应该是if (*word==*s)(你比较存储在指向位置的字符,而不是指针);
  3. 指针的前进,但它应该回到s这个词的开头,在达到它的末尾后,即s -= len之后的for (j=...);
  4. s++word++不需要后,您将指针前移相同的数量,无论您是否找到匹配项;
  5. flag应在声明时用1初始化。
+0

谢谢,完美的工作 – saharz

2

啊,那应该是if(*word == *s)你需要使用间接运算符。同样如hackss所说,flag = 0;必须在第一个for()循环之外。

+0

哦,是啊只是滑了那一个@BLUEPIXY谢谢 –

+0

它没有解决问题 – saharz

1

无关,但可能用于fgets代替scanf或使用scanf函数与长度说明例如

scanf("%99s",string1) 

事情,我可以看到错误的第一眼:

  1. 你的循环越过MAX_STRING,它只需要超过s的长度。
  2. 您的迭代应该只覆盖字符串的长度,但索引从0开始而不是1。for (i=0; i<=len; i++)不正确。
  3. 您还应该比较指针的内容而不是指针本身。 if(*word == *s)
  4. 指针提前逻辑不正确。也许把指针当作数组可以简化你的逻辑。

另一个不相关的点:另一种不相关的算法是将字符串1的字符散列到地图上,然后检查字符串2的每个字符并查看它是否存在于地图中。如果所有字符都存在,则返回1,如果遇到第一个不存在的字符,则返回0.如果仅限于使用ASCII字符,则散列函数非常容易。您的ASCII字符串越长,第二种方法的性能就越好。

0

Rajivanswer中扩展想法,您可以增量构建字符映射,如下面的containsLetters2()

containsLetters1()函数是一个简单的使用标准字符串函数的蛮力实现。如果字符串(干草堆)中有N个字符,单词(针)中有M个字符,则当查找单词的字符只出现在最后一个字符时,它的最坏情况表现为O(N * M)搜索的字符串。 strchr(needle, needle[i]) >= &needle[i]测试是一个优化,如果有可能在针重复的字符;如果不会有任何重复,这是一个悲观(但它可以被删除,代码仍然工作正常)。

containsLetters2()函数最多搜索一遍字符串(haystack)一次,最多搜索一次字(针)一次,以获得最差情况的O(N + M)性能。

#include <assert.h> 
#include <stdio.h> 
#include <string.h> 

static int containsLetters1(char const *haystack, char const *needle) 
{ 
    for (int i = 0; needle[i] != '\0'; i++) 
    { 
     if (strchr(needle, needle[i]) >= &needle[i] && 
      strchr(haystack, needle[i]) == 0) 
      return 0; 
    } 
    return 1; 
} 

static int containsLetters2(char const *haystack, char const *needle) 
{ 
    char map[256] = { 0 }; 
    size_t j = 0; 

    for (int i = 0; needle[i] != '\0'; i++) 
    { 
     unsigned char c_needle = needle[i]; 
     if (map[c_needle] == 0) 
     { 
      /* We don't know whether needle[i] is in the haystack yet */ 
      unsigned char c_stack; 
      do 
      { 
       c_stack = haystack[j++]; 
       if (c_stack == 0) 
        return 0; 
       map[c_stack] = 1; 
      } while (c_stack != c_needle); 
     } 
    } 
    return 1; 
} 

int main(void) 
{ 
    assert(containsLetters1("this_is_a_long_string","gagahats") == 1); 
    assert(containsLetters1("this_is_a_longstring","gaz") == 0); 
    assert(containsLetters1("hello","p") == 0); 

    assert(containsLetters2("this_is_a_long_string","gagahats") == 1); 
    assert(containsLetters2("this_is_a_longstring","gaz") == 0); 
    assert(containsLetters2("hello","p") == 0); 
} 

既然你可以看到测试的整个范围,这是不喜欢彻底的测试什么,但我相信它应该做工精细,不管有多少重复的有针。

+1

有人会关心解释为什么这可以保证倒票吗? –

1

下面是一个单行解决方案,与C程序员的亨利斯宾塞的Commandment 7保持一致。

#include <string.h> 

/* 
* Does l contain every character that appears in r? 
* 
* Note degenerate cases: true if r is an empty string, even if l is empty. 
*/ 

int contains(const char *l, const char *r) 
{ 
    return strspn(r, l) == strlen(r); 
} 

但是,问题陈述不是关于字符,而是关于字母。为了解决问题中的字面意思,我们必须从正确的字符串中删除非字母。例如,如果r是字error-prone,并且l不包含连字符,则函数返回0,即使l包含r中的每个字母。

如果允许我们修改字符串r,那么我们可以做的是将字符串中的每个非字母替换为它包含的字母之一。 (如果它不包含字母,那么我们就可以把它变成一个空字符串。)

void nuke_non_letters(char *r) 
{ 
    static const char *alpha = 
    "abcdefghijklmnopqrstuvwxyz" 
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 

    while (*r) { 
    size_t letter_span = strspn(r, alpha); 
    size_t non_letter_span = strcspn(r + letter_span, alpha); 
    char replace = (letter_span != 0) ? *r : 0; 
    memset(r + letter_span, replace, non_letter_span); 
    r += letter_span + non_letter_span; 
    } 
} 

这也带来了另一个缺陷:字母可以是大写和小写。如果右边的字符串是A,而左边的字符串只包含小写字母a,那么我们就失败了。

解决此问题的一种方法是通过tolowertoupper过滤两个字符串的字符。

第三个问题是一个字母不仅仅是英文字母的26个字母。一个现代化的程序应该使用宽字符,并识别所有的Unicode字母,以便它可以用任何语言工作。

当我们处理所有这些问题时,我们可能会超过一些其他答案的长度。

+0

+1 - 我看了看'strcspn()',并没有提出解决方案,但是我没有发现反向参数上的'strspn()'。做得好。井井有条。 –