1

プログラムはノードの挿入昇順ソートを実行する必要があります。最初に名前をチェックし、名前が等しい場合はIDをソートする必要があります。正しくソートされない問題が何であるかわかりません。

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

typedef struct nd{
int id;
char name[20];
float gpa;
struct nd *next;
}node;


typedef node *list;

//---------------------------------------------------------------

int insertlist(list *head,char *buffer)
{
list p,q,n;
int m,num,k,sc;
p=(list)malloc(sizeof(node));
num=sscanf(buffer,"%d %s %f",&(p->id),(p->name),(&p->gpa));
if(num!=3)
 {
  printf("info not complete\n");
  free(p);
  return 1;
 }
else
{

   if(!*head)
   {
    *head=p;
    p->next = NULL;
   }
//******** sorting tthe names and ids for equal names
   else if(sc=strcmp((*head)->name,p->name)> 0 || ((sc == 0) && ((*head)->id > p->id)))
      {//head is modified
        p->next=*head;
        *head=p;
      }

   else{
        n=*head;
        q=n->next;
        while(q && ((sc=strcmp(q->name,p->name)<0) || ((sc == 0) && (q->id < p->id))))
          {
           n=q;
           q=q->next;
          }
       n->next=p;
       p->next=q;
       }
}

return 0;
}

//------------------------------------------------------

int main()
{
int id,r;
list head,p;
FILE *fp;
char c,buffer[100],filename[10];
if ((fp=fopen("student.txt","r"))==NULL)
{
  printf("error opening %s",filename);
  exit(1);
}
else
 {
head=NULL;

while(fgets(buffer,100,fp)!=NULL)
   {
    buffer[strlen(buffer)-1]=='\0';
    r=insertlist(&head,buffer);
   }
fclose(fp);
 }

for(p=head;p!=NULL;p=p->next)
  printf("%d  %s  %f\n\n",p->id,p->name,p->gpa);
}

内容の例student.txt

121513 ala 45.00
121510 wang 21.00 
145852 frank 26.00 
151515 ala 25.00 
4

3 に答える 3

1

headはポインターなので、関数でheadを変更するには、headにポインターを渡す必要があります。ポインタへのポインタ。

このように宣言します:

int insertlist(list **head,char *buffer)

このように呼んでください:

r=insertlist(&(&head),buffer);

そして、関数内で、ポインタを参照解除するために参照するすべての場所を変更します。

于 2013-01-15T12:02:24.880 に答える
1

まず、これを修正します。

buffer[strlen(buffer)-1]=='\0';

これは平等の比較です。割り当てではありません。バッファの最後で改行を破棄しようとしていると思います。その場合は、最初に改行する行あることを確認する必要があります(たとえば、入力ファイルの最後の行が1行で終わらない場合があります。それでも、これは壊れているため、修正する必要があります。 。

次に、ソートループに問題があります。論理的な欠陥を取り除いて(そして他の課外活動もかなり)、読みやすく、したがって理解しやすいものを以下に含めます:

int insertlist(list *head, char *buffer)
{
    list p=NULL, q=NULL;
    int sc=0;

    /* allocate new node */
    p = calloc(1, sizeof(*p));
    if(3 != sscanf(buffer,"%d %s %f",&(p->id),(p->name),(&p->gpa)))
    {
        printf("info not complete\n");
        free(p);
        return 1;
    }

    /* initially wire p->next to our list head. then, walk list, 
       advancing p->next. break on first "less" condition */
    p->next = *head;
    while (p->next)
    {
        /* broken out here for clarity; break on first "less" */
        sc = strcmp(p->name, p->next->name);
        if (sc < 0 || (sc == 0 && p->id < p->next->id))
            break;
        q = p->next;
        p->next = q->next;
    }

    /* non-null means we wire q->next to p */
    if (q) 
        q->next = p;

    /* else p is the new head; what head was prior is already in p->next */
    else
        *head = p;

    return 0;
}

次の入力ファイルでテスト済み:

0001 Brook 3.50
0002 James 3.51
0003 Katie 3.52
0004 James 3.87
0005 Brook 2.70

結果:

1  Brook  3.500000

5  Brook  2.700000

2  James  3.510000

4  James  3.870000

3  Katie  3.520000

これらの問題を修正しようとするとき、およびコードがどのように機能するかを確認したいときは、デバッガーでコードをシングルステップで実行することを強くお勧めします。

最後に、怪我に侮辱を加えないために、あなたは決してあなたのリストを解放しません。つまり、プログラムの終了時にメモリリークが発生します。これは、実行中に「不良」レベルでメモリリークが発生した場合に次ぐものです。そのリストを歩き、その記憶を解放します。入るのは良い習慣です。


リンクリストを解放するためのOPリクエストの編集:

main()今のところ、前の終わりにreturnステートメントで十分です。いつか、これを行うための関数を作成することを検討する必要があります。

while (head)
{
    list p=head;
    head=head->next;
    free(p);
}
于 2013-01-15T12:52:04.950 に答える
1

並べ替えの問題は、演算子の優先順位の1つです

<より>も優先順位が高く=、最初に評価されてから割り当てが行われます。

したがって、文字列は次の2つの場所で比較されます。

else if(sc=strcmp((*head)->name,p->name)> 0 || ((sc == 0) && ((*head)->id > p->id)))
...
while(q && ((sc=strcmp(q->name,p->name)<0) || ((sc == 0) && (q->id < p->id))))

間違っている。scとの値をそれぞれ取得していますstrcmp((*head)->name,p->name)> 0strcmp(q->name,p->name)<0これは常に1または0、決してなりません-1

コードをそのように調整するだけの場合:

else if((sc=strcmp((*head)->name,p->name))> 0 || ((sc == 0) && ((*head)->id > p->id)))
...
while(q && (((sc=strcmp(q->name,p->name))<0) || ((sc == 0) && (q->id < p->id))))

あなたはそれが機能しているのを見るでしょう。話の教訓:括弧や角かっこをけちにしようとしないでください。追加するのに何も費用がかからず、コードが明確になり、このようなデバッグの頭痛の種を減らすことができます。

于 2013-01-15T13:22:51.927 に答える