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

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

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

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

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

Q&A

解決済

3回答

758閲覧

構造体のポインタ渡しの仕組みが分からない

misemi

総合スコア8

C

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

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

0グッド

0クリップ

投稿2020/02/01 13:40

Cで英単語の処理をするプログラムを作るために、二分探索木を実装しています。
二分探索木で新たなノードを追加する再帰関数を書いたのですが、構造体のポインタに関して分からない事があったので質問させてください。

二分探索木のノードの構造体と、ノードを追加する関数↓

C

1/* ノードの構造体 */ 2typedef struct BINNODE { 3 char *word; 4 struct BINNODE *pLeft; 5 struct BINNODE *pRight; 6} BinNode; 7 8/* pNodeの木にwordをメンバ変数に持つノードを追加する再帰関数 */ 9BinNode *apndNode(BinNode *pNode, char *word) { 10 int cond; 11 if(pNode == NULL) { 12 pNode = (BinNode*)malloc(sizeof(BinNode)); 13 pNode->word = (char*)malloc(strlen(word)+1); 14 strcpy(pNode->word, word); 15 pNode->pLeft = pNode->pRight = NULL; 16 } 17 else if(strcmp(pNode->word, word) < 0) 18 pNode->pRight = apndNode(pNode->pRight, word); //"pNode->pRight = "はなぜいる? 19 else 20 pNode->pLeft = apndNode(pNode->pLeft, word); //"pNode->pLeft = "はなぜいる? 21 return pNode; 22}

下から4行目と2行目の
**pNode->pRight = apndNode(pNode->pRight, word);
pNode->pLeft = apndNode(pNode->pRight, word);
なのですが、pNode->pRight,pNode-pLeftへ代入する処理をなくしてapndNode関数だけ呼び出すようにした場合、ノードへの変更が反映されなくなりました。(例えば
apndNode(rootNode->pRight, hoge)**を呼び出してもrootNode->pRightはNULLのままになってしまう)

ポインタ渡しならば、apndNode(pNode->pRight, word)を呼び出すだけでpNode->pRightのメモリの確保やメンバ変数の変更も反映されると思うのですが、なぜ代入をしないと反映されなくなるのでしょうか。

実行環境はvscodeです。
拙い説明ですが、回答よろしくお願いいたします。

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

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

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

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

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

guest

回答3

0

ベストアンサー

ポインタ渡しならば、apndNode(pNode->pRight, word)を呼び出すだけでpNode->pRightのメモリの確保やメンバ変数の変更も反映されると思うのですが、

C

1void allocate(int* p) { 2 p = (int*)malloc(sizeof(int)); /* 領域を確保する */ 3} 4 5int main() { 6 int* int_ptr = NULL; 7 allocate(int_ptr); 8 ... 9}

上記コードで、int_ptr には allocate() で確保された領域がセットされない

C

1void fill_zero(int n) { 2 n = 0; 3} 4 5int main() { 6 int n = 123; 7 fill_zero(n); 8 ...

これ↑で n == 0 とならないのと同じ理由で。

ポインタ値を変更したいなら

C

1void allocate(int** p) { 2 *p = (int*)malloc(sizeof(int)); /* 領域を確保する */ 3} 4 5int main() { 6 int* int_ptr = NULL; 7 allocate(&int_ptr); 8 ... 9}

あるいは

C

1int* allocate() { 2 return (int*)malloc(sizeof(int)); /* 領域を確保する */ 3} 4 5int main() { 6 int* int_ptr = NULL; 7 int_ptr = allocate(); 8 ... 9}

投稿2020/02/01 14:02

episteme

総合スコア16614

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

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

misemi

2020/02/01 14:20

ポインタにアドレスを代入しても元のポインタには反映されないんですね。とても腑に落ちました。 丁寧に例示して頂きありがとうございます。
guest

0

ちょっと難しい回答になるけど・・・
ポインタを渡しても呼び出し元の変数には代入できないので、呼び出し元で変数に代入する必要があります。
参照渡しできる言語(C++, C#, PHP)ならば、呼び出した先で呼び出し元の変数に代入できるので、呼び出し元での代入を省略できます。

参照渡しにしたコードを書いてみました。g++でコンパイルして実行してみてください。

c++

1#include <iostream> 2#include <cstring> 3 4#define MAX 1000000 5 6/* ノードの構造体 */ 7typedef struct BINNODE { 8 char *word; 9 struct BINNODE *pLeft; 10 struct BINNODE *pRight; 11} BinNode; 12 13/* pNodeの木にwordをメンバ変数に持つノードを追加する再帰関数 */ 14void apndNode(BinNode *&pNode, const char *word) { 15 int cond; 16 if(pNode == NULL) { 17 pNode = (BinNode*)malloc(sizeof(BinNode)); //呼び出し元の変数に代入 18 pNode->word = (char*)malloc(strlen(word)+1); 19 strcpy(pNode->word, word); 20 pNode->pLeft = pNode->pRight = NULL; 21 } 22 else if(strcmp(pNode->word, word) < 0) 23 apndNode(pNode->pRight, word); //呼び出し元での"pNode->pRight = "は不要 24 else 25 apndNode(pNode->pLeft, word); //呼び出し元での"pNode->pLeft = "は不要 26} 27 28int main(){ 29 struct BINNODE *root = NULL; 30 apndNode(root, "hello"); 31 apndNode(root, "world"); 32 printf("word: %s\n", root->word); 33 printf("right: %s\n", root->pRight ? root->pRight->word : "NULL"); 34 printf("left: %s\n", root->pLeft ? root->pLeft->word: "NULL"); 35}

投稿2020/02/01 13:51

編集2020/02/01 15:16
shiracamus

総合スコア5406

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

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

misemi

2020/02/01 14:22

参照渡しの例とても参考になりました。C++などではこちらを使っていきたいと思います。ありがとうございます。
guest

0

pNode->pRigh
というのは、
(*pNode).pRigh
と同じです。
そこから考えてみればいいかと。

投稿2020/02/01 13:51

y_waiwai

総合スコア87749

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問