1

クラスの devowelling プログラムをほぼ完成させましたが、リンク リスト ノードから母音がないことを検出しようとした while ループに到達したときに、メモリ アクセス違反エラーが発生しました。私がこれを行った方法はとてつもなく非効率的であることに気づきました(多くの論理ORチェック)が、これを行う他の方法に苦労していました. まったく混乱しています。あまり助けを期待していませんが、ポインタ (: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

次のような用途があるかもしれません:

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

私が何をしたかわかりますか?私は目前の問題 (文字が英語の母音かどうかを判断する) の小さな部分を取り、それをプログラムの独立した部分に分割しました。

次に、標準ライブラリ関数を使用して繰り返しの性質を削減することは、もちろん、コードをより読みやすくするために一般的に良い別のアイデアです。

あなたのコードに関して、あなたの連結リストコードは多くの場所でひどく壊れています。リンクされたリストを使用してこれを本当に実装する必要があるかどうかを検討する必要があります。これは文字列変換であり、C の文字列は通常、連結リストとして扱われません。もちろん、これは授業だったので、あなたの手は縛られていると思います。

次に、実行するすべてのリスト操作を詳しく調べ、意味があるかどうかを分析する必要があります。メモリの有効性について考えNULL、リストの最後を超えないようにチェックし、(再び)これらの操作を専用の関数に分割して、互いに分離して作成、検討、およびテストできるかどうかを検討します。解決しようとしている実際の問題から。

于 2012-11-01T08:14:09.433 に答える
1
while(...HORRIBLE CONDITION DEREFERENCING llist->next SNIPPED...)
    llist = llist->next;
    temp = llist->next->next;
    free(llist->next);
    llist->next = temp;
 } 

このコードには、少なくとも 2 つの致命的な問題があります。まず第一に、C++ ではインデントはブロックを決定しませんが、{} はブロックを決定し、ペアがありません。次に、次の要素があるかどうか、またはリストが終了しているかどうかを確認せずに、llist->next の内容にアクセスします。

于 2012-11-01T08:36:55.257 に答える
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 c問題がないことを確認するために、おそらく署名済みの強制に注意してくださいunsigned char

次のレベルのパフォーマンスでは、関数を、最初に使用する前に適切に初期化されis_vowel()たグローバル配列にアクセスするマクロに置き換えます。vowelsこれはオーケストレーションが難しくなります (ただし、<ctype.h>などのマクロで通常発生することisalpha()です)。

また、この名前は、ヘッダーis_vowel()によって予約されている名前とは無関係であることにも注意してください。<ctype.h>

§7.31.2 文字の扱い<ctype.h>

is¶1またはで始まる関数名to、および小文字を<ctype.h>ヘッダーの宣言に追加できます。

于 2012-11-01T10:19:21.047 に答える