構造体について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
マーチ

構造体について

#1

投稿記事 by マーチ » 6年前

また学校で課題が出てしまい明日中に提出をしなくてはならず、
これ以上は限界と感じたため再び皆様にお力をお貸しいただければと思い書き込ませていただきました。

名前を連結リストに追加、削除、そしてリストの中身の表示、反転を行うプログラムを作っております。

出来ない点は
・数値しか入出力ができない。名前なので文字列を扱えるようにしたい。
(文字列ができるように''やchar、%sなど試みていましたがエラーがあまりにも多く、数値だけ認識できる状態のコードを書き込ませていただきます)

・名前と苗字を両方入力したい。
(そのためには判定も増やさなくてはならず出力した場合も名前の間に半角スペースが必要であり、どのように書き込めばいいかあまりにも難しく理解することができなかった)

コードを書き込ませていただきます。
本当にプログラミングの右も左もわからない初心者ですが、何卒ご指摘助言よろしくお願いいたします。

コード:

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

//構造体の宣言
typedef struct list{    
    int data;
    struct list *next;
} LIST;

//headはリストの先頭 tailはリストの末尾
LIST *head,*tail;    

//指定の数字が存在するかのフラグ
int non=0;    

//リストの中身の表示
void display_list(LIST *p) {

    if(p == NULL)
        printf("リストには何もありません\n");
    else{
        printf("現在のリストの中身は\n");

        printf("%d", p->data);
        p = p->next;
        while(p != NULL){
            printf(",%d", p->data);
            p = p->next;
        }
        printf("\nです\n");
    }
    
}

//リストの作成
LIST *new_list(int x, LIST *y){

    LIST *c = (LIST *)malloc(sizeof(LIST));
    c->data = x;
    c->next = y;
    return c;

}

//リストに名前を追加
void add_list(int x){
    LIST *p;
    p = new_list(x, NULL);

    if(head == NULL)
        head = tail = p;
    else{
        tail->next = p;
        tail = p;
    }
}

//リストから名前を削除
void delete_list(int x){
    LIST *p, *q;
    q = p = head;

    while(p != NULL && x != p->data){
        q = p;
        p = p->next;
    }
    
	//見つからなかった場合
    if (p == NULL){    
        non=1;
        return;
    }
	//先頭にあった場合
    if (q == p) head = head->next;
    
    //それ以外 消えた部分を連結
    else q->next = p->next;    
    free(p);
}

//リストの中身を反転
LIST *reverse(LIST *list){
    LIST *p;
    
    if(list==NULL) return list;

    p=new_list(list->data,NULL);
    tail=p;

    while(list->next!=NULL){

        list=list->next;
        p=new_list(list->data,p);

    }

    return p;
}


int main(){
    int a,add,del;
    head=NULL;
    tail=NULL;

    while(1){

        printf("        コマンド表   \n");
        printf("0 : リストの表示 1 : リストの追加\n");
        printf("2 : リストの削除 3 : リストの反転\n");
        printf("     4 : 処理の終了 \n");
        printf("コマンドを入力してください:");

        scanf("%d",&a);

	//リストの表示
        if(a==0){
            display_list(head);

	//リストの追加
        }else if(a==1){

            printf("追加する名前は?(最大40字)\n");
            scanf("%d",&add);
            add_list(add);
            printf("%d を追加しました!\n",add);

	//リストの削除
        }else if(a==2){

            printf("削除する名前は?\n");
            scanf("%d",&del);
            delete_list(del);
            if(non==0){
                printf("%d を削除しました!\n",del);
            }else if(non==1){
                printf("その名前はリストに存在しません!\n");
                non=0;
            }

        //リストの反転
        }else if(a==3){
            head=reverse(head);
            printf("反転が完了しました\n");

        //処理の終了    
        }else if(a==4){
			printf("終了します\n");
            break;
        }

   }
   return(0);
}


かずま

Re: 構造体について

#2

投稿記事 by かずま » 6年前

マーチ さんが書きました: ・数値しか入出力ができない。名前なので文字列を扱えるようにしたい。
(文字列ができるように''やchar、%sなど試みていましたがエラーがあまりにも多く、数値だけ認識できる状態のコードを書き込ませていただきます)

コード:

7c7
<     int data;
---
>     char *data;
25c25
<         printf("%d", p->data);
---
>         printf("%s", p->data);
28c28
<             printf(",%d", p->data);
---
>             printf(",%s", p->data);
37c37
< LIST *new_list(int x, LIST *y){
---
> LIST *new_list(const char *x, LIST *y){
40c40
<     c->data = x;
---
>     c->data = strdup(x);
47c47
< void add_list(int x){
---
> void add_list(const char *x){
60c60
< void delete_list(int x){
---
> void delete_list(const char *x){
64c64
<     while(p != NULL && x != p->data){
---
>     while(p != NULL && strcmp(x, p->data) != 0){
79c79
<     free(p);
---
>     free(p->data); free(p);
103c103
<     int a,add,del;
---
>     int a; char add[40 + 2], del[40 + 2];
125c125
<             scanf("%d",&add);
---
>             scanf("%41s",add); if (strlen(add) > 40) return 1;
127c127
<             printf("%d を追加しました!\n",add);
---
>             printf("%s を追加しました!\n",add);
133c133
<             scanf("%d",&del);
---
>             scanf("%41s",del); if (strlen(del) > 40) return 1;
136c136
<                 printf("%d を削除しました!\n",del);
---
>                 printf("%s を削除しました!\n",del);
シングルバイト文字にしか対応していません。
最大文字数のチェックはしていますが、
エラー処理をせず、終了させています。
マルチバイト文字(平仮名や漢字など)を許すのなら、変更が必要です。
環境(OS, コンパイラ、文字コードなど)を教えてください。
マーチ さんが書きました: ・名前と苗字を両方入力したい。
(そのためには判定も増やさなくてはならず出力した場合も名前の間に半角スペースが必要であり、どのように書き込めばいいかあまりにも難しく理解することができなかった)
名前の入力の仕様と決めてください。

コード:

追加する苗字は?(最大40字)
Minamoto
追加する名前は?(最大40字)
Shizuka
それとも

コード:

追加する苗字と名前は?(スペースで区切り最大40字)
Minamoto Shizuka

マーチ

Re: 構造体について

#3

投稿記事 by マーチ » 6年前

またまたありがとうございます。
コマンドや苗字などは余計だったようで、入力した文字列を連結リストを利用して反転し表示させるものを作れればよいそうです。

ある程度作っているのですが何故か最後に入力した文字列が全てに上書きされてしまいます・・・どうすればよいのでしょうか?
(確認用も残っております、すみません)

コード:

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

//構造の宣言
typedef struct list{    
    char *name;
    //int data;    
struct list *next;
}LIST;

LIST *head,*p;

int main()
{
    int f=1, g=1, n;
	char data[40], handan[50];
    
     
while ((g = 1)) {

	n = 0;

    head = NULL;

    while ((f = 1)) {
        n++;
        printf("%d人目の名前を入力してください\n", n);

		fgets(data, sizeof(data), stdin);
        p = (LIST *)malloc(sizeof(LIST));   	
 printf("%d\n", p);
       	p->name =data;
		p->next =head;
		head = p;
printf("%s\n", p->name);
printf("%d\n", head);

        printf("名前の入力を続けますか?");
		printf("Yesならyを、Noならnを入力してください.\n");
        fgets(handan, sizeof(handan), stdin);

        while(handan[0] != 'y' && handan[0] != 'n'){
            printf("yかnを入力してください.\n");
           fgets(handan, sizeof(handan), stdin);
        }

        if(handan[0] == 'n') break;
	
	}
	    p = head;
 printf("%d\n", p);
	    while(p !=NULL){
 printf("%d\n", p);
			printf("%s\n", p->name);
			p = p->next;
 printf("%d\n", p);
		}

    printf("再度リストを作りますか??");
    printf("Yesならyを、Noならnを入力してください.\n");
    fgets(handan, sizeof(handan), stdin);
	   
    while(handan[0] != 'y' && handan[0] != 'n'){
        printf("yかnを入力してください.\n");
        fgets(handan, sizeof(handan), stdin);
    }

    if(handan[0] == 'n') break;

}

free(p);

return(0);

}
環境は
OS     windows7
コンパイラ VisualStudio2010 gccで
文字コード UTF-8
です。
最初の文字に改行やスペースを入れた場合エラーメッセージを入れたり、
40字数制限もしたいのですが、
一番の問題はリストの追加と表示が出来ないことです。
よろしくお願いいたします。

アバター
みけCAT
記事: 6293
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: 構造体について

#4

投稿記事 by みけCAT » 6年前

マーチ さんが書きました:ある程度作っているのですが何故か最後に入力した文字列が全てに上書きされてしまいます・・・どうすればよいのでしょうか?
きちんと入力した文字列用の領域を毎回確保し、そこに入力した文字列を保存し、リストに格納すればいいです。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

かずま

Re: 構造体について

#5

投稿記事 by かずま » 6年前

マーチ さんが書きました: ある程度作っているのですが何故か最後に入力した文字列が全てに上書きされてしまいます・・・どうすればよいのでしょうか?
名前を入れるところが、入力用のバッファである data ひとつしかないからです。

p->name = data; を p->name = strdup(data); に
変更すると解決するはずです。
strdup は、次のようになっていて、
新しい領域を確保して、そこに data の内容をコピーしてくれます。

コード:

char *strdup(const char *s)
{
	char *p = malloc(strlen(s) + 1);
	if (p == NULL) return NULL;
	strcpy(p, s);
	return p;
}
マーチ さんが書きました: 環境は
OS     windows7
コンパイラ VisualStudio2010 gccで
文字コード UTF-8
コンパイル(ビルド)の手順はどうしていますか?

マーチ

Re: 構造体について

#6

投稿記事 by マーチ » 6年前

ありがとうございます!おかげで処理を行えるようになりました!

ですがヒープの開放ができず困っております。
やってはいるのですが処理が正しく出来ていないようで・・・

コード:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
//構造体の宣言
typedef struct list{    
    char *name;
    
struct list *next;
}LIST;
 
LIST *head,*p,*tail;

//文字列を新しく確保したメモリにコピーしてポインタを返す
char *strdup(const char *s)
{
    char *p = malloc(strlen(s) + 1);
    if (p == NULL) return NULL;
    strcpy(p, s);
    return p;
}

int main()
{
//宣言
    int f=1, g=1, n;
    char data[40], handan[50];
    
     
while ((g = 1)) {
 
    n = 0;
 
    head = NULL;

    //入力処理 連結リストのheadに文字列を入れる
    while ((f = 1)) {
        n++;
        printf("\n%d人目の名前を入力してください\n", n);
 
        fgets(data, sizeof(data), stdin);
        p = (LIST *)malloc(sizeof(LIST));       
        p->name = strdup(data);       
p->next = head;
        head = p;
 
  //リストへの入力を続けるか、リストを表示させるかの処理
        printf("名前の入力を続けるならyを、");
        printf("リストを表示させるならnを入力してください.\n");
        fgets(handan, 50, stdin);
 
//yとnではない場合
        while(handan[0] != 'y' && handan[0] != 'n'){
           printf("yかnを入力してください.\n");
           fgets(handan, 50, stdin);
        }
 
        if(handan[0] == 'n') break;
    
    }
//headから読む
        p = head;
printf("\nリストの中身は\n");
        while(p !=NULL){
            printf("%s", p->name);
            p = p->next;
        }
    printf("です\n");

//再度作るかどうか
    printf("\n再度リストを作りますか?");
    printf("Yesならyを、Noならnを入力してください.\n");
    fgets(handan, sizeof(handan), stdin);
       
    //yとnではない場合
    while(handan[0] != 'y' && handan[0] != 'n'){
        printf("yかnを入力してください.\n");
        fgets(handan, sizeof(handan), stdin);
    }
 
    if(handan[0] == 'n') break;

	//メモリの解放
    LIST *q;
        q = p = head;
        while(p !=NULL){
p = q;
            p = p->next;
free(q);
}

}

        //確認用
        head = p;
        printf("\nリストの中身は\n");
        while(p !=NULL){
            printf("%s", p->name);
            p = p->next;
        }
        printf("です\n");

return(0);

}
今はVisualStudio2010を利用しているのでコンパイルはその手順どおり行っております。

アバター
へにっくす
記事: 630
登録日時: 8年前
住所: 東京都

Re: 構造体について

#7

投稿記事 by へにっくす » 6年前

まず言えることは、インデントをそろえることです。
No.1のコードはそろってる(完全ではないですが)のに
それ以外のコードはめちゃめちゃです。

インデントをそろえるというのは、何も回答者のためだけではない。
コードを見やすくするというのは、整理するのと同じことで、質問者自身、問題に気付かせやすくするものです。
疎かにしてはいけません。

Visual Studioを使っているのなら
全部選択して、編集メニュー→詳細→選択範囲のフォーマット
を行ってください。自動的にインデントしてくれます。
(ショートカットならCtrlキーを押したままA K Fです
またはCtrlキーを押したままA E Fでも同様→VisualStudio2010でコード整形
それを行ってからコードを張り付けてくださいね。
written by へにっくす

マーチ

Re: 構造体について

#8

投稿記事 by マーチ » 6年前

了解です、失礼しました。

閉鎖

“C言語何でも質問掲示板” へ戻る