1

我几乎已经完成了类的去元音程序,但是当它到达一个while循环时遇到了内存访问冲突错误,我试图检测链表节点中元音的缺失。我意识到我这样做的方式非常低效(许多逻辑或检查),但我正在努力寻找其他方式来做到这一点。完全糊涂了。不希望有太多帮助,但任何指针(:S)将不胜感激。

https://gist.github.com/3992412

或者,复制粘贴:

#include <iostream>
#include <stdlib.h>

struct NODE {
 char letter;
 struct NODE *next;
};

int vowelcheck(struct NODE *llist, int num);
void addnode(struct NODE *llist, char c);
void showsentence(struct NODE *llist);
void devowel(struct NODE *llist);

int main(void) {
 char charin;
 int input = 1;
 struct NODE *llist;
 int nodeno = 0;
 llist = (struct NODE *)malloc(sizeof(struct NODE));
 llist->letter = 0;
 llist->next = NULL;

 while(input != 0) {
  printf("\n\n --Disemvoweler--\n");
  printf("(0) Quit\n");
  printf("(1) Enter sentence\n");
  printf("(2) Disemvowel\n");
  printf("(3) Display parsed sentence\n");
  scanf("%d", &input);

  switch(input) {
   case 0: //exit
   default:
    printf("Exiting\n");
    break;
   case 1: //sentence input
    printf("\nEnter sentence, finish sentence with full stop (.) :\n");
     do
     {
      charin=getchar();
      addnode(llist, charin);
     }
     while (charin != '.');
    break;
   case 2: //remove vowels
    printf("Your choice: `Disembvowel'\n");
    while(llist->next != NULL) {
     devowel(llist);
     llist = llist->next;
    }
    printf("Disembvoweled!\n");
    break;
   case 3: //show sentence in memory (devoweled or not)
    printf("\n Parsed sentence: \n");
    showsentence(llist);
    break;
   }
  }

 free(llist);
 return(0);
}

void showsentence(struct NODE *llist) {
 while(llist->next != NULL) { //while not the last link (ie not full stop)
  printf("%c ", llist->letter); //print letter
  llist = llist->next; //move to next link
 }
}

void addnode(struct NODE *llist, char charin) {
 while(llist->next != NULL)
 llist = llist->next;
 llist->next = (struct NODE *)malloc(sizeof(struct NODE));
 llist->next->letter = charin;
 llist->next->next = NULL;
}

void devowel(struct NODE *llist) {
 struct NODE *temp;
 temp = (struct NODE *)malloc(sizeof(struct NODE));
if(llist->letter == 'A' || llist->letter == 'a' || llist->letter == 'E' || llist->letter == 'e' || llist->letter == 'I' || llist->letter == 'i' || llist->letter == 'O' || llist->letter == 'o' || llist->letter == 'U' || llist->letter == 'u')
{
  /* remove the node */
  temp = llist->next;
  free(llist);
  llist = temp;
 } else {
  while(llist->next->letter != 'A' || llist->next->letter != 'a' || llist->next->letter != 'E' || llist->next->letter != 'e' || llist->next->letter != 'I' || llist->next->letter != 'i' || llist->next->letter != 'O' || llist->next->letter != 'o' || llist->next->letter != 'U' || llist->next->letter != 'u')
    llist = llist->next;
    temp = llist->next->next;
    free(llist->next);
    llist->next = temp;
 }
}
4

3 回答 3

1
while(...HORRIBLE CONDITION DEREFERENCING llist->next SNIPPED...)
    llist = llist->next;
    temp = llist->next->next;
    free(llist->next);
    llist->next = temp;
 } 

这段代码至少有两个致命的问题。首先,在 C++ 中,缩进不能确定块,{} 可以,而且你缺少一对。其次,您访问 llist->next 的内容而不检查是否有下一个元素,或者列表是否已经结束。

于 2012-11-01T08:36:55.257 回答
1

您可能会使用以下内容:

int character_is_vowel(char ch)
{
  return strchr("AEIOUaeiou", ch) != NULL;
}

看看我做了什么,那里?我处理了手头的一小部分问题(确定一个字符是否是英语中的元音)并将其分解为程序的一个独立部分。

然后,使用标准库函数来减少重复性当然是另一个通常有益于使代码更具可读性的想法。

关于您的代码,您的链表代码在许多地方都严重损坏。您应该考虑是否真的必须使用链表来实现这一点。这是一个字符串转换,C 中的字符串通常不被视为链表。当然,既然这是上课,我猜你的手被束缚了。

然后,您应该仔细查看所做的所有列表操作,并分析它们是否有意义。考虑内存有效性,检查以确保NULL您不会超出列表的末尾,以及(再次)是否有可能将这些操作分解为您可以独立编写、思考和测试的专用函数从您要解决的实际问题出发。

于 2012-11-01T08:14:09.433 回答
0

关于山脉和鼹鼠丘的警句浮现在脑海中。

这是一个工作程序,它读取输入行,然后取消这些行。

样品运行

$ ./disemvowel
What's the point of including vowels if you're going to strip 'em all?
Entered: What's the point of including vowels if you're going to strip 'em all?
Disemvowelled: Wht's th pnt f ncldng vwls f y'r gng t strp 'm ll?
$

样品来源

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

static int is_vowel(char c)
{
    return(strchr("aeiouAEIOU", c) != 0);
}

int main(void)
{
    char line[4096];
    while (fgets(line, sizeof(line), stdin) != 0)
    {
        printf("Entered: %s", line);
        char *dst = line;
        char *src = line;
        char c;
        while ((c = *src++) != '\0')
        {
            if (!is_vowel(c))
                *dst++ = c;
        }
        *dst = '\0';
        printf("Disemvowelled: %s", line);
    }
    return(0);
}

如果字符串不包含元音,它会逐字节地复制字符串。但是,在循环中添加一个条件来查看是否dst < src会使事情复杂化而带来的好处可以忽略不计(从长远来看,它会减慢速度)。如果要加快速度,可以使用表驱动is_vowel()函数:

static int is_vowel(char c)
{
    static vowels[256];
    if (vowels['a'] == 0)
    {
        unsigned char *v = "aeiouAEIOU";
        while (*v != '\0')
            vowel[*v++] = 1;
    }
    return vowels[(unsigned char)c];
}

注意可能签名的强制char cunsigned char确保没有问题。

下一级别的性能将is_vowel()用一个访问全局数组的宏替换该函数,该全局数组vowels在首次使用之前已适当初始化。这更难编排(但这是宏通常发生的情况,<ctype.h>例如isalpha())。

还要注意,该名称is_vowel()避开了<ctype.h>标题保留的名称:

§7.31.2 字符处理<ctype.h>

¶1 以isor开头的函数名称to和一个小写字母可以添加到<ctype.h>标头中的声明中。

于 2012-11-01T10:19:21.047 回答