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

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

ただいまの
回答率

90.61%

  • C

    3575questions

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

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

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 195

wagon

score 3

 前提・実現したいこと

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

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

なし

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

#include <stdio.h>
#include "mystack.h"

int main(void)
{
    int menu;
    char *data[100];
    struct student *seito[100];
    char n[16];
    int m,e;
    int i=0;
    CharStack s;

    if (Initialize(&s, 64) == -1) {
        puts("スタックの生成に失敗しました。");
        return 1;
    }

    while (1) {
        char x[48],x1[16],x2[16],x3[16];
        printf("現在のデータ数:%d / %d\n", Size(&s), Capacity(&s));
        printf("(1)プッシュ  \n(2)ポップしてデータベースに格納 (3)データベースの値を表示 (4)スタック内表示 (0) 終了:");
        scanf("%d", &menu);

        if (menu == 0) break;

        switch (menu) {
        case 1: /*--- プッシュ ---*/
            printf("データ:");
            scanf("%s %s %s", x1,x2,x3);
            sprintf(x,"%s %s %s",x1,x2,x3);
            if (Push(&s, x) == -1)
                puts("\aエラ-:プッシュに失敗しました。");
            break;

        case 2: /*--- ポップしてデータベースに格納 ---*/
            if (Pop(&s, &data[i]) == -1)
                puts("\aエラ-:ポップに失敗しました。");
            else
                printf("ポップしたデータは%sです。\n", data[i]);
                //ポップしたデータを文字列と数値に変換
                sscanf(data[i],"%s%d%d",n,&m,&e);
                //構造体の配列に格納
                seito[i] = set_student(n,m,e);
                i++;
            break;
        /*---データベースの値を表示---*/
        case 3:
            print_all_student(seito,i);
            break;
        case 4:
            Print(&s);
        }
    }

    Terminate(&s);

    return 0;
}


### 使用したヘッダファイル内の関数

C

ifndef MYSTACK_H

define MYSTACK_H

include <stdio.h>

include <stdlib.h>

include <string.h>

typedef struct
{
int max;    //スタックのサイズ
int ptr;    //スタックのポインタ
char **stk;    //スタック(の先頭要素へのポインタ)
} CharStack;

struct student
{
char name[12];
int math;
int eng;
};
/*--- スタックの初期化 ---*/
int Initialize(CharStack *s, int max)
{
s->ptr = 0;
if ((s->stk = calloc(max, sizeof(char *))) == NULL) {
s->max = 0;                                /* 配列の生成に失敗 */
return -1;
}
s->max = max;
return 0;
}
/*--- スタックの後始末 ---*/
void Terminate(CharStack *s)
{
if (s->stk != NULL)
free(s->stk);        /* 配列を破棄 */
s->max = s->ptr = 0;
}
/*--サイズ確認--*/
int Size(const CharStack *s)
{
return s->ptr;
}
/*--- スタックにデータをプッシュ ---*/
int Push(CharStack *s, char *x)
{
if (s->ptr >= s->max)                        /* スタックは満杯 */
return -1;
s->stk[s->ptr++] = x;
return 0;
}

/*--- スタックからデータをポップ ---*/
int Pop(CharStack *s, char **x)
{
if (s->ptr <= 0)                            /* スタックは空 */
return -1;
*x = s->stk[--s->ptr];
return 0;
}
/*--- スタックの容量 ---*/
int Capacity(const CharStack *s)
{
return s->max;
}
/*--- 全データの表示 ---*/
void Print(const CharStack *s)
{
int i;

for (i = 0; i < s->ptr; i++)        /* 底→頂上に走査 */
printf("%s", s->stk[i]);
putchar('\n');
}

void print_all_student(struct student *seito[],int ninzu)
{
int i;
for(i=0;i<ninzu;i++)
{
printf("Name:%s\nMath:%d\nEng:%d\n",seito[i]->name,seito[i]->math,seito[i]->eng);
}
}
//struct student構造体オブジェクトのメンバに値を格納する関数
struct student *set_student(char *n, int m, int e)
{
struct student *ps = NULL;
ps = (struct student*)malloc(1 * sizeof(struct student));
if(ps == NULL)
{
puts("記憶域の確保に失敗しました");
return NULL;    
}
strcpy(ps->name, n);
ps->math = m;
ps->eng = e;
return ps;
}

endif

```

 試したこと

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

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

visual C++ 2010

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+4

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

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

 追記

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

Push(&s, strdup(x))

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

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

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/25 00:55

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

    キャンセル

  • 2018/06/25 01:08

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

    キャンセル

  • 2018/06/25 22:48

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

    キャンセル

+1

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/25 00:33

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

    キャンセル

  • 2018/06/25 07:03

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

    キャンセル

  • 2018/06/25 23:01

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

    キャンセル

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

  • ただいまの回答率 90.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C

    3575questions

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