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

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

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

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

ソート

複数のデータを、順序性に従って並べ替えること。 データ処理を行う際に頻繁に用いられ、多くのアルゴリズムが存在します。速度、容量、複雑さなどに違いがあり、高速性に特化したものにクイックソートがあります。

ポインタ

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

Q&A

解決済

3回答

6182閲覧

ポインタのポインタがよくイメージできない

nsd24

総合スコア9

C

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

ソート

複数のデータを、順序性に従って並べ替えること。 データ処理を行う際に頻繁に用いられ、多くのアルゴリズムが存在します。速度、容量、複雑さなどに違いがあり、高速性に特化したものにクイックソートがあります。

ポインタ

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

2グッド

1クリップ

投稿2018/05/15 13:43

編集2018/05/16 05:03

前提・実現したいこと

※初投稿です。不手際がありましたら申し訳ございません。
①2つの文字列(char *a,char *b)に対して、辞書順を判定する関数int hantei(char *a,char *b)を作成せよ。この関数の戻り値として、aがbより前(辞書順で)にくる場合は1、aとbが同じ文字列の場合は0、それ以外の場合は-1とする。
②バブルソートを用いて文字列配列(char **argv)を辞書順に並び替える関数void sort(char **argv,int n)を作成せよ。また、引数nは文字列の個数を表し、①のhantei関数を用いること。
バブルソートの参考として以下のコードが書いてありました。

C

1void bubble(int list[],int n) 2{ 3 int i,t; 4 5 for(n=n-1;n>=0;n--){ 6 for(i=0;i<n;i++){ 7 if(list[i]>list[i+1]){ 8 t=list[i]; 9 list[i]=list[i+1]; 10 list[i+1]=t; 11 } 12 } 13 } 14} 15

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

①については自力でコードをかけました。(一度間違えましたが)

C

1#include<stdio.h> 2 3#define N 100 4 5int hantei(char *a,char *b); 6 7int main(void) 8{ 9 int ans; 10 char a[N],b[N]; 11 12 printf("辞書順を判定するぞー!\n"); 13 printf("文字列aを入力してくれ。"); 14 gets(a); 15 printf("文字列bを入力してくれ。"); 16 gets(b); 17 18 ans=comp_d(a,b); 19 if(ans==1){ 20 printf("aの文字列の方が前だぞ。\n"); 21 } 22 else if(ans==0){ 23 printf("aとbは同じ文字列だぞ。\n"); 24 } 25 else if(ans==-1){ 26 printf("bの方が前だぞ。\n"); 27 } 28 29 return 0; 30} 31 32int hantei(char *a,char *b) 33{ 34 int i; 35 for ( i = 0; *(a+i) != '\0' && *(b+i) != '\0'; i++ ) { 36 if(*(a+i)<*(b+i)){ 37 return 1; 38 } 39 if(*(a+i)>*(b+i)){ 40 return -1; 41 } 42 } 43 if(*(a+i)!='\0'){ 44 return 1; 45 } 46 if(*(b+i)!='\0'){ 47 return -1; 48 } 49 return 0; 50} 51 52

②についてが、正直に言うとほとんどわかりませんでしたが、回答者の皆様のおかげですこしずつイメージ自体はつかめるようになってきました。そこで、コードを書いてみましたがいくつかエラーが出てしまいました。
具体的な書き方がつかめておらず、何点か不明な点があります。

〇わからないこと

 ・//str=(char *)malloc(sizeof(char)*n);では、エラーがでなかったがその直下にあるようにfor文でループさせるとエラーがでます。なぜでしょうか?また、このnは文字列の個数(何個の文字列を入力するか)なのですが、本来は1つ1つの文字列の長さ(文字が何個あるか)を入れるべきなのですが、文字列の長さを計算するにはまず文字列を入力しなければならないわけで、??となっております。
・sort関数内で、tはint型で宣言されています。ここに代入するには文字列の先頭アドレスを代入すればいい、という認識であっているのでしょうか?(問題には参考としてバブルソートが書かれているだけなので無理して合わせる必要はない、とは思いますが)

〇わかったこと
・//str=(char *)malloc(sizeof(char)*n);の意味
char型のサイズ(1バイト)×n(ここでは文字列の個数(何個の文字列を入力するか)ですが)分のメモリをmalloc関数で確保し、それを(char *)に明示的に変換している。(左辺のポインタ変数strにあわせている?)
・関数sortの引数にポインタのポインタ(アドレス)があるが、そこにはポインタ変数のアドレスを渡せばよい。
・参考として↑にあるバブルソートには文字列がint型に入っているが、そこにはポインタのアドレスを渡せばよい。

C

1#include<stdio.h> 2#include<stdlib.h> 3 4int hantei(char *a, char *b); 5void sort(char **argv,int n); 6 7int main(void) 8{ 9 char *str; 10 char enter; 11 int i,n; 12 13 printf("複数の文字列配列を辞書順に並び替えるぞ\n"); 14 printf("文字列の個数入力して→"); 15 scanf("%d",&n); 16 17 enter=getchar(); 18 19 //str=(char *)malloc(sizeof(char)*n); //下記にて説明有り 20 for(i=0;i<n;i++){ 21 (str+i)=(char *)malloc(sizeof(char)*n); //「左辺値が必要」とエラーがでます 22 } 23 24 for(i=0;i<n;i++){ 25 printf("%dつ目の文字列を入力しよ> ",i+1); 26 scanf("%s",str+i); 27 } 28 29 sort(&str,n); 30 31 for(i=0;i<n;i++){ 32 printf("辞書順に文字列を出力します。\n"); 33 printf("%s\n",str+i); 34 } 35 36 return 0; 37} 38 39void sort(char **argv,int n) 40{ 41 int i,j,t; 42 43 if(n==1){ 44 printf("データ1個しかないですよ\n"); 45 } 46 else{ 47 for(i=n-1;i>=0;i--){ //「char *型はint型に変換できない」とエラーが出ます。 48 for(j=0;j<n;j++){ 49 if(hantei(*(argv+j),*(argv+j+1))==-1){ 50 t=*(argv+j); 51 *(argv+j)=*(argv+j+1); 52 *(argv+j+1)=t; 53 } 54 } 55 } 56 } 57} 58 59int hantei(char *a,char *b) 60{ 61 int i; 62 63 for(i=0;*(a+i)!='\0' && *(b+i)!='\0';i++){ 64 if(*(a+i)<*(b+i)){ 65 return 1; 66 } 67 else if(*(a+i)>*(b+i)){ 68 return -1; 69 } 70 } 71 if(*(a+i)!='\0'){ 72 return -1; 73 } 74 else if(*(b+i)!='\0'){ 75 return 1; 76 } 77 return 0; 78}

試したこと

まずポインタのポインタ(ダブルポインタ)のイメージがわかなかったため以下のようなコードを拾ってて、どのような動きをしているのか自分で図を描いて理解しました。(以下参照)

C

1#include<stdio.h> 2 3#define N 50 4 5int main(void) 6{ 7 //普通のポインタ 8 int t; 9 char *str1,*str2,*str3; 10 char fig[]="abcdefghijk"; 11 12 str1=fig; 13 printf("%c\n",*str1); //文字の出力 14 15 str2=fig; 16 for(t=0;*(str2+t)!='\0';t++){ 17 printf("%c",*(str2+t)); //文字列の出力 18 } 19 printf("\n"); 20 21 str3=fig; 22 printf("%s\n",fig); //文字列の出力 23 24 //ダブルポインタの理解1 25 char *figure1,**figure2; 26 char buf1[N]="あいうえお"; 27 char buf2[N]="かきくけこ"; 28 29 figure1=buf1; 30 figure2=&figure1; 31 *figure2=buf2; 32 33 printf("%s\n",figure1); 34 35 //ダブルポインタの理解2 36 char *month[3]={"January","February","March"}; 37 char **p1,**p2,**p3; 38 int i,j; 39 40 p1=month; 41 p2=month; 42 p3=month; 43 44 for(i=0;i<3;i++){ 45 printf("%s\n",*(p1+i)); 46 } 47 48 for(i=0;i<3;i++){ 49 printf("%s\n",*p2); 50 p2++; 51 } 52}

![イメージ説明
↑上のプログラム内の //ダブルポインタの理解1 の図解

他にも様々なサイトを見ましたが、よくわからず
・配列だと要素数を宣言しないといけないが、ポインタのポインタとmalloc関数を使えばメモリを余分に使うことなく処理できる。
ということくらいしかわかりませんでした。
また、普通のポインタについてはアドレスなど、動きが理解しやすいのですがポインタのポインタについてはどのような考えをしながらコードを追っていけばいいのかがわかりません。

未熟者ですがどうかご指導よろしくお願いします。

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

使用しているツールは、BCC Developerで、コンパイラはBorland C++ Compilerを使用しています。

keicha_hrs, yohhoy👍を押しています

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

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

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

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

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

guest

回答3

0

ベストアンサー

ポインタのポインタ、じゃなくて、ポインタのアドレス、です。
アドレスが入る変数がポインタと呼ばれます。その変数のアドレスを取ってくると、ポインタのアドレスですねー

#ってそのままやんっ


んで、なんでポインタのアドレスを引数に取るのか、といえば、
その引数の内容を関数から変更したいから、なんですね。

C

1void uniuni(int* p) 2{ 3 *p = 1; 4} 5 6と同様に、 7 8void ahiahi(char** p) 9{ 10 *p ="uhiuhi"; 11} 12 13int i; 14uniuni(&i); 15// i は1 16 17char* p; 18ahiahi(&p); 19// p は"uhiuhi"を指している

ってことができるようになるんですねー

投稿2018/05/15 13:49

編集2018/05/15 13:54
y_waiwai

総合スコア87747

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

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

nsd24

2018/05/15 15:05 編集

ご回答ありがとうございます! ポインタのアドレス、たしかにそう考えると読みやすいですね! 明日また↑の②の問題を頑張って解いてみようと思います! ポインタのアドレスを使うのは、ポインタの内容(アドレス)をさらに関数で変更したりするっていう考えなんですね!ありがとうございます!
guest

0

「何らかのデータ型へのポインタ」が本当に理解できればそれでOK。ポインタのポインタも単に「指し示す何らかの型」がポインタ型なだけなのです。

投稿2018/05/15 14:19

a_saitoh

総合スコア702

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

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

nsd24

2018/05/15 15:20

ご回答ありがとうございます! 言葉としては分かるのですが、書くとなるとなかなか…(多分ただの経験不足) また明日(今日)勉強してみます! ありがとうございます!
a_saitoh

2018/05/15 15:35

「理解できた実感」にとらわれない方が良いですよ。理解できた実感があることと理解できてることは結構違うので
kaizen_nagoya

2018/05/15 22:49

The C puzzle bookに、ポインタのポインタと、ポインタとポインタのポインタの実例があります。printfでそれぞれの値を出力させて理解するという方法です。当方では、報告に「わかったこと」と「わからなかったこと」を必ず記載していただいています。「わかったこと」だけあって「わからなかったこと」がない場合には、わかっていないと判断します。実際、その場合にほとんど全ての場合にわかっていないことが確認できています。わかれば、わかるほど、わからないことが増えるというのが経験則です。a_saitoh さんが書かれているように、「理解できた実感があることと理解できてることは結構違う」は経験則です。実用的に使う場合、どこまでわかっていればいいかは、現在何がわかっていないかを書いてもらって、その項目が、今回には必要ないかどうかで対応の切り分けにしています。
nsd24

2018/05/16 05:05

a_saitohさん 返信ありがとうございます!理解することにばかり目を向けずまずはコードを書いていきたいと思います!
nsd24

2018/05/16 09:57 編集

kaizen_nagoyaさん ご回答ありがとうございます! 私はとある試験のために勉強していて、(学生です)その過去問題として上記にあげた問題が出てきたため質問させていただきました。現時点でわかったこと・わからないことを上記に編集しましたので、ご指導よろしくお願いします。
guest

0

・配列だと要素数を宣言しないといけないが、ポインタのポインタとmalloc関数を使えばメモリを余分に使うことなく処理できる。

これは、間違い。
malloc関数を使っても、メモリは使います。
ただ、メモリの使い方が違って、配列だと、多めに確保する必要があるが、malloc関数での確保では、必要な量だけの確保で済みます。ただし、その都度、確保なので、ちょっと遅いかも。また、管理上の都合で、余分なメモリを使います。 (今だと無視できる量かも)

また、

char *month[3]={"January","February","March"};

だと、3つの文字列の配列となります。この文字列は一般には書換えできません。

他にも色々とありますが、とりあえず。

投稿2018/05/15 13:59

pepperleaf

総合スコア6383

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

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

nsd24

2018/05/15 15:15

ご回答ありがとうございます! malloc関数では時間がかかるかわりに 動的(入力によって)にメモリを確保できるっていう認識でよいのでしょうか? まだポインタの配列等認識が甘いところがあるのでまた明日(今日)勉強してみます。ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問