简体   繁体   English

C中字符串中的反元音

[英]reverse vowels in string in c

I'm a beginner programmer. 我是一个初学者程序员。 I was trying out the problem of reversing vowels in a string. 我正在尝试反转一串元音的问题。

Ex: input: zabedfigu, output: zubidfega 例如:输入:zabedfigu,输出:zubidfega

When I run the following code, I get a runtime error. 当我运行以下代码时,出现运行时错误。 I've tried to change the conditions within incrementing the pointer pc1 upto only upto the middle index etc., but that either gives me a runtime error or doesn't give me the required output. 我试图在将指针pc1递增到仅直到中间索引等范围内更改条件,但是这给了我运行时错误或没有给我所需的输出。 I'd like some help on what to do to make my code work as well as any new way of solving the problem. 我想要一些有关如何使我的代码正常工作以及解决问题的新方法的帮助。 TIA. TIA。

#include<stdio.h>

char* reverseVowels(char* str)
{
    char *pc1, *pc2;
    int i;
    pc1 = &str[0];
    for(i=0; str[i]!='\0';++i)
        ;
    pc2 = &str[i-1];

    while(pc1!=pc2)
    {
      if((*pc1=='a')||(*pc1=='e')||(*pc1=='i')||(*pc1=='o')||(*pc1=='u'))
      {
        while(pc2!=pc1)
        {
            if((*pc2=='a')||(*pc2=='e')||(*pc2=='i')||(*pc2=='o')||(*pc2=='u'))
            {
              char temp;
              temp = *pc1;
              *pc1 = *pc2;
              *pc2 = temp;
              ++pc2;
              break;
            }
            else
              ++pc2;
        }
        ++pc1;
      }
      else
        ++pc1;
    }
    //return str;
    return NULL;
}
int main()
{
    char string[20], *pstr;
    scanf("%s", string);
    //pstr = reverseVowels(string);
    //printf("%s", pstr);
    reverseVowels(string);
    printf("%s", string);
    return 0;
}

The problem here is that you are incrementing both pointers the one in the 0 position, and the one in the end position. 这里的问题是,您将两个指针都在0位置递增,并将一个指针在结束位置递增。 The first pointer should increment, and the second one should decrement, thus instead of doing this: 第一个指针应该增加,第二个指针应该减少,因此不要这样做:

++pc2;

You should do this 你应该做这个

--pc2;

The problem is occurring when you are going to increment the pointer variable value of pc2 , instead of decrementing the pointer variable pc2 value like this --pc . 当您要递增pc2的指针变量值,而不是像--pc这样递减指针变量pc2值时, --pc

Updated 更新

According to cleblanc 's comment , my previous answer was not working for an input like abade , so then I changed the code to fix that problem. 根据cleblanc评论 ,我先前的答案不适用于abade类的输入,因此我更改了代码以解决该问题。

#include <stdio.h>

char* reverseVowels(char* str)
{
    char *pc1, *pc2;
    int i;
    pc1 = &str[0];
    for(i=0; str[i]!='\0';++i)
        ;
    pc2 = &str[i-1];

    while(pc1<pc2)
    {
      if((*pc1=='a')||(*pc1=='e')||(*pc1=='i')||(*pc1=='o')||(*pc1=='u'))
      {
        while(pc2!=pc1)
        {
            if((*pc2=='a')||(*pc2=='e')||(*pc2=='i')||(*pc2=='o')||(*pc2=='u'))
            {
              char temp;
              temp = *pc1;
              *pc1 = *pc2;
              *pc2 = temp;
              --pc2;
              break;
            }
            else
              --pc2;
        }
        ++pc1;
      }
      else
        ++pc1;
    }
    //return str;
    return NULL;
}
int main()
{
    char string[20], *pstr;
    scanf("%s", string);
    //pstr = reverseVowels(string);
    //printf("%s", pstr);
    reverseVowels(string);
    printf("%s\n", string);
    return 0;
}

You have several answers and comments pointing out the fundamental flaw in your code — that you're incrementing pc2 instead of decrementing it. 您有几个答案和注释,指出了代码的基本缺陷-您要递增pc2而不是递减pc2 However, I think your algorithm is more complicated than need be. 但是,我认为您的算法比需要的复杂。 You could: 你可以:

  • Subject at all times to pc1 < pc2 : 始终受pc1 < pc2
    • If pc1 is not pointing at a vowel, increment it 如果pc1没有指向元音,则将其递增
    • If pc2 is not pointing at a vowel, decrement it 如果pc2没有指向元音,则将其递减
    • If the pointers are different, swap the vowels and adjust the pointers 如果指针不同,请交换元音并调整指针

With test code, and with the addition of an is_vowel() function which detects both upper-case and lower-case vowels, I ended up with: 使用测试代码,并添加了一个is_vowel()函数,该函数可以同时检测大写和小写的元音,最后我得到了:

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

static inline int is_vowel(int c)
{
    c = tolower(c);
    return (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u');
}

static void reverse_vowels(char *string)
{
    char *p1 = string;
    char *p2 = p1 + strlen(p1);     // '\0' is not a vowel

    while (p1 < p2)
    {
        while (p1 < p2 && !is_vowel((unsigned char)*p1))
            p1++;
        while (p1 < p2 && !is_vowel((unsigned char)*p2))
            p2--;
        if (p1 != p2)
        {
            char c = *p1;
            *p1++ = *p2;
            *p2-- = c;
        }
    }
}

int main(void)
{
#ifdef INTERACTIVE
    char line[1024];
    while (fgets(line, sizeof(line), stdin) != NULL)
    {
        line[strcspn(line, "\n")] = '\0';
        printf("Input:  [%s]\n", line);
        reverse_vowels(line);
        printf("Output: [%s]\n", line);
    }
#else
    char strings[][40] =
    {
        "",
        "a",
        "b",
        "ab",
        "abe",
        "abeci",
        "nnnnummmmmmmmmmmmippppoqq",
        "AbleWasIEreISawElba",
        "A Man, A Plan, A Canal - Panama!"
    };
    enum { NUM_STRINGS = sizeof(strings) / sizeof(strings[0]) };

    for (int i = 0; i < NUM_STRINGS; i++)
    {
        printf("Input:  [%s]\n", strings[i]);
        reverse_vowels(strings[i]);
        printf("Output: [%s]\n", strings[i]);
    }
#endif /* INTERACTIVE */
    return 0;
}

You can compile it with -DINTERACTIVE to give you an interactive test, or by default it gives a fixed set of tests. 您可以使用-DINTERACTIVE进行编译,以提供交互式测试,或者默认情况下,它提供一组固定的测试。

Default output: 默认输出:

Input:  []
Output: []
Input:  [a]
Output: [a]
Input:  [b]
Output: [b]
Input:  [ab]
Output: [ab]
Input:  [abe]
Output: [eba]
Input:  [abeci]
Output: [ibeca]
Input:  [nnnnummmmmmmmmmmmippppoqq]
Output: [nnnnommmmmmmmmmmmippppuqq]
Input:  [AbleWasIEreISawElba]
Output: [ablEWasIerEISawelbA]
Input:  [A Man, A Plan, A Canal - Panama!]
Output: [a Man, a Plan, a CAnal - PAnamA!]

Sample interactive session (my program was called rv61 ): 样本交互式会话(我的程序称为rv61 ):

$ rv61

Input:  []
Output: []
a
Input:  [a]
Output: [a]
b
Input:  [b]
Output: [b]
ab
Input:  [ab]
Output: [ab]
ae
Input:  [ae]
Output: [ea]
abcde
Input:  [abcde]
Output: [ebcda]
ablewasiereisawelba
Input:  [ablewasiereisawelba]
Output: [ablewasiereisawelba]
palindromic nonsense 
Input:  [palindromic nonsense]
Output: [pelendromic nonsinsa]
vwlsmssng
Input:  [vwlsmssng]
Output: [vwlsmssng]
AManAPlanACanal-Panama!
Input:  [AManAPlanACanal-Panama!]
Output: [aManaPlanaCAnal-PAnamA!]
  a big and complex sentence with multiple words of a number of lengths and so on  
Input:  [  a big and complex sentence with multiple words of a number of lengths and so on  ]
Output: [  o bog and cemplox sentunca woth moltepli wurds if e nember ef longths and si an  ]
$

Note that the testing tests a number of degenerate cases — an empty string, a string with no vowels, a string with one vowel, etc. The palindromic tests benefit from supporting mixed case — it's hard to spot that vowels have been swapped if they're all lower case and the text is a palindrome. 请注意,该测试会测试多种退化的情况-空字符串,不带元音的字符串,不带元音的字符串等。回文测试得益于支持混合大小写的情况-很难发现如果元音已被交换,都是小写,文字是回文。

Another test that could be applied is to reverse the vowels twice; 可以应用的另一个测试是将元音反转两次。 the output should be the same as the input. 输出应与输入相同。 Conservation tests can be important. 保存测试可能很重要。 (If you had a sort which didn't preserve all the elements in the array but added random new ones and/or dropped initial ones, you wouldn't be happy. But that's a topic for another day.) (如果您的排序没有保留数组中的所有元素,而是添加了随机的新元素和/或删除了初始元素,那么您将不会感到高兴。但这是另一天的主题。)

Having a simple test harness along the lines shown can be helpful for library functions. 沿所示方向使用简单的测试工具有助于库功能。 Many of my library functions have a #ifdef TEST#endif at the end to allow them to be tested for sanity. 我的许多库函数的末尾都有一个#ifdef TEST#endif ,以便对其进行完整性测试。 The best tests verify that the result is what is expected; 最好的测试可以验证结果是否符合预期。 these ones are lazy and leave it to visual inspection to validate the output. 这些都是懒惰的,将其留给目视检查以验证输出。 If it was a library function, there'd be a header to declare the function which would be #include d in the source, and the function would not be static . 如果它是一个库函数,那么将有一个标头声明该函数,该标头在源代码中将是#include d,而该函数将不是static (My default compilation options require either a declaration of the function before it is defined, or the function must be static . I make functions static in sample code like this since there's no other file referencing the function, so there's no need for a header to declare the function, and only headers should declare externally visible functions.) (我的默认编译选项或者需要一个功能的声明中定义之前,或函数必须是static 。我做的功能static样品中像这样的代码,因为没有其他文件中引用的功能,所以没有必要为一个头声明该函数,并且只有标头应该声明外部可见的函数。)

Note too that the is_vowel name is carefully chosen to avoid the reserved names in the C standard: 还要注意, is_vowel名称是精心选择的,以避免在C标准中保留名称:

Function names that begin with either is or to , and a lowercase letter may be added to the declarations in the <ctype.h> header. isto开头的函数名称以及小写字母可以添加到<ctype.h>标头中的声明中。

Using isVowel() would have been OK too; 使用isVowel()也可以。 using isvowel() would be using a reserved name. 使用isvowel()将使用保留名称。


Bill Woodger commented : Bill Woodger 评论

Why the comment about '\\0' not being a vowel? 为什么有关“ \\ 0”不是元音的评论? ...

With the code as shown, after the initialization of p2 , it is true that *p2 == '\\0' . 使用所示的代码,在p2初始化之后,确实*p2 == '\\0' The observation the '\\0' is not a vowel matters if the string is non-empty because if it matched the is_vowel() predicate, the null byte could be moved to some point earlier in the string, truncating it. 如果字符串非空,则观察到'\\0'不是元音很重要,因为如果字符串与is_vowel()谓词匹配,则可以将空字节移至字符串中的较早位置,从而将其截断。

Suppose the function was reverse_controls() instead of reverse_vowels() and the test used iscntrl() instead of is_vowel() . 假设函数是reverse_controls()而不是reverse_vowels() ,并且测试使用了iscntrl()而不是is_vowel() Then the code would have to handle it differently for a non-zero length string because the null byte would be reported as a control character and that would send things awry — it would be swapped with the first other control character (if there was another) in the string, truncating the string. 然后,对于非零长度的字符串,代码将不得不以不同的方式处理它,因为空字节将被报告为控制字符,并且会发送错误消息-将与第一个其他控制字符(如果有另一个)交换在字符串中,截断字符串。 That is not what's intended. 那不是故意的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM