質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

2回答

3640閲覧

二回以上関数を使用するとデータが置き換わってしまいます。

wagon

総合スコア11

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2018/06/24 13:57

編集2018/06/24 15:27

前提・実現したいこと

C言語でスタックを実現する関数を作っています
2回Push関数でスタック内にデータを入れて、Print関数でスタック内を見てみると1回目に入れたはずのデータも2回目に入れたデータ置き換わってしまいます。

発生している問題・エラーメッセージ

なし

該当のソースコード(main関数)

C

1#include <stdio.h> 2#include "mystack.h" 3 4int main(void) 5{ 6 int menu; 7 char *data[100]; 8 struct student *seito[100]; 9 char n[16]; 10 int m,e; 11 int i=0; 12 CharStack s; 13 14 if (Initialize(&s, 64) == -1) { 15 puts("スタックの生成に失敗しました。"); 16 return 1; 17 } 18 19 while (1) { 20 char x[48],x1[16],x2[16],x3[16]; 21 printf("現在のデータ数:%d / %d\n", Size(&s), Capacity(&s)); 22 printf("(1)プッシュ \n(2)ポップしてデータベースに格納 (3)データベースの値を表示 (4)スタック内表示 (0) 終了:"); 23 scanf("%d", &menu); 24 25 if (menu == 0) break; 26 27 switch (menu) { 28 case 1: /*--- プッシュ ---*/ 29 printf("データ:"); 30 scanf("%s %s %s", x1,x2,x3); 31 sprintf(x,"%s %s %s",x1,x2,x3); 32 if (Push(&s, x) == -1) 33 puts("\aエラ-:プッシュに失敗しました。"); 34 break; 35 36 case 2: /*--- ポップしてデータベースに格納 ---*/ 37 if (Pop(&s, &data[i]) == -1) 38 puts("\aエラ-:ポップに失敗しました。"); 39 else 40 printf("ポップしたデータは%sです。\n", data[i]); 41 //ポップしたデータを文字列と数値に変換 42 sscanf(data[i],"%s%d%d",n,&m,&e); 43 //構造体の配列に格納 44 seito[i] = set_student(n,m,e); 45 i++; 46 break; 47 /*---データベースの値を表示---*/ 48 case 3: 49 print_all_student(seito,i); 50 break; 51 case 4: 52 Print(&s); 53 } 54 } 55 56 Terminate(&s); 57 58 return 0; 59} 60 61 62### 使用したヘッダファイル内の関数 63```C 64#ifndef MYSTACK_H 65#define MYSTACK_H 66 67#include <stdio.h> 68#include <stdlib.h> 69#include <string.h> 70 71typedef struct 72{ 73 int max; //スタックのサイズ 74 int ptr; //スタックのポインタ 75 char **stk; //スタック(の先頭要素へのポインタ) 76} CharStack; 77 78struct student 79{ 80 char name[12]; 81 int math; 82 int eng; 83}; 84/*--- スタックの初期化 ---*/ 85int Initialize(CharStack *s, int max) 86{ 87 s->ptr = 0; 88 if ((s->stk = calloc(max, sizeof(char *))) == NULL) { 89 s->max = 0; /* 配列の生成に失敗 */ 90 return -1; 91 } 92 s->max = max; 93 return 0; 94} 95/*--- スタックの後始末 ---*/ 96void Terminate(CharStack *s) 97{ 98 if (s->stk != NULL) 99 free(s->stk); /* 配列を破棄 */ 100 s->max = s->ptr = 0; 101} 102/*--サイズ確認--*/ 103int Size(const CharStack *s) 104{ 105 return s->ptr; 106} 107/*--- スタックにデータをプッシュ ---*/ 108int Push(CharStack *s, char *x) 109{ 110 if (s->ptr >= s->max) /* スタックは満杯 */ 111 return -1; 112 s->stk[s->ptr++] = x; 113 return 0; 114} 115 116/*--- スタックからデータをポップ ---*/ 117int Pop(CharStack *s, char **x) 118{ 119 if (s->ptr <= 0) /* スタックは空 */ 120 return -1; 121 *x = s->stk[--s->ptr]; 122 return 0; 123} 124/*--- スタックの容量 ---*/ 125int Capacity(const CharStack *s) 126{ 127 return s->max; 128} 129/*--- 全データの表示 ---*/ 130void Print(const CharStack *s) 131{ 132 int i; 133 134 for (i = 0; i < s->ptr; i++) /* 底→頂上に走査 */ 135 printf("%s", s->stk[i]); 136 putchar('\n'); 137} 138 139void print_all_student(struct student *seito[],int ninzu) 140{ 141 int i; 142 for(i=0;i<ninzu;i++) 143 { 144 printf("Name:%s\nMath:%d\nEng:%d\n",seito[i]->name,seito[i]->math,seito[i]->eng); 145 } 146} 147//struct student構造体オブジェクトのメンバに値を格納する関数 148struct student *set_student(char *n, int m, int e) 149{ 150 struct student *ps = NULL; 151 ps = (struct student*)malloc(1 * sizeof(struct student)); 152 if(ps == NULL) 153 { 154 puts("記憶域の確保に失敗しました"); 155 return NULL; 156 } 157 strcpy(ps->name, n); 158 ps->math = m; 159 ps->eng = e; 160 return ps; 161} 162 163#endif

試したこと

Pushを二回行い、スタック内を確認したら問題が発生したので、Pushの関数かmain関数の変数に問題があるのかもしれないということがわかった。

補足情報(FW/ツールのバージョンなど)

visual C++ 2010

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

Pushに渡しているxがmainのローカル変数とかではないですか?
stkは各要素をchar*で保存していてすべて同じ変数を示しているためxを書き換えれば要素の値も変わってしまいます。
stkのポインタのアドレスを見れば多分全部同じになっていると思います。

保存するときにmalloc & strcpy, またはstrdupでメモリを確保して文字列を別の領域にコピーしなければいけません。
いらなくなったとき(Popして値を使用し終わった後)のfreeもお忘れなく。

追記

現状のコードだとwhileで繰り返す度にxは存在が消えるので大変危険なコードです。
一番簡単なのは

C

1Push(&s, strdup(x))

とすれば新しいバッファを確保して文字列をコピーして返してくれます。
Popで得たデータはスタックにはもう残っていませんから、帰ってきたものを使い終わったらfreeで開放します。

C

1char* p; 2if (Pop(&s, &p) == -1) 3 puts("\aエラ-:ポップに失敗しました。"); 4else { // <------------------------ ブロックで囲むこと 5 printf("ポップしたデータは%sです。\n", p); 6 //ポップしたデータを文字列と数値に変換 7 sscanf(p,"%s%d%d",n,&m,&e); 8 //構造体の配列に格納 9 seito[i] = set_student(n,m,e); 10 i++; 11 free(p); // 必要なくなったので開放 12}

あとTerminateでも開放が必要です。

C

1for(int i=0; i<s->ptr; i++) 2 free(s->stk[i]); // 残っている分を全て開放 3free(s->stk);

投稿2018/06/24 14:15

編集2018/06/25 13:33
toki_td

総合スコア2850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

wagon

2018/06/24 15:55

Pushに渡すxを具体的にはどのように変更を加えればよいのでしょうか?
wagon

2018/06/24 16:08

読み込むxを1ループごとに別の場所に保存していき、それをPushの引数にとるというように変更すればよいのでしょうか
wagon

2018/06/25 13:48

おかげで解決しました。ありがとうございました。
guest

0

そのPush、Pop関数はint*を読み書きしてますが、

sprintf(x,"%s %s %s",x1,x2,x3); if (Push(&s, x) == -1)

x の出どころが不明です。
こいつの本体はどこに存在してるんでしょうか。

投稿2018/06/24 14:11

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

wagon

2018/06/24 15:33

main関数内でchar x[48]で定義しました。 ソースコードをすべて記載したのでそちらを確認していただけると助かります。
y_waiwai

2018/06/24 22:03

push/pop でアドレスを操作してますが、そのアドレスの刺し先は保存されません 2回目のpushの際、xの内容は上書きされ、pushされるアドレスxの値も同一のものになります
wagon

2018/06/25 14:01

解決しました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問