ポインタの初歩で学びたい!関数で戻り値を複数返す方法とは?

このQ&Aのポイント
  • ポインタを使った変数のアドレス代入や値の代入について説明してくれませんか?
  • 関数で戻り値を1つしか返せないため、複数の値を返す方法について勉強中です。
  • ポインタはデスクトップのショートカットアイコンのようなもので、使い方がわかりにくいと感じています。
回答を見る
  • ベストアンサー

ポインタの初歩でお聞きしたいです。

今カレンダーを作っていて、西暦と月を入力するとその時のカレンダーを表示するだけです。 関数で、「関数は戻り値を1ッコしか返せないので、複数個返すことができるようにするには」みたいなところを勉強中です。 int main() { int year,month,week,days;       : getYearMonth(&year,&month);       : return 0; } getYearMonth(int *py,int *pm) { printf("西暦と月を2009 3のようにスペースで区切って入力してください\n"); while(1) { scanf("%d %d",py,pm); //*ここがちょっとわからないところです* if((*pm>=1)&&(*pm<=12)){ //1から12月まででそれ以外の数字なら break; // printf("入力間違いです\n") } return; } "*pyや*pm"がscanfのところにいくと'*'とって'&'をつけないのは"pyとpm"がアドレスを指すってモノっていうことですか? getYearMonth(&year,&month);ではyearとmonthには'&'アドレスのマークをつけますけれど、それは下とおなじですよね? -------------------------------------------------------------- int x; //変数の宣言 int *p; //ポインタ変数の宣言 p=&x; //ポインタ変数の初期化 ここが、getYearMont(&year,&month);と一緒? *p=10; //値(アドレス)の代入 scanf()で値を入れてるところと同じ? ということでしょうか? ちょっと、ポイントで引っかかってます。 ポインタってデスクトップのショートカットアイコンみたいなものです よって、前になんかで見たんですが。イメージがつかみづらいです。 もしかしたら、質問自体ちぐはぐな事を言ってたらすみません。

質問者が選んだベストアンサー

  • ベストアンサー
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.1

じゃあ、仮想的にアドレスを割り振って考えて見ましょう。 int year,month,week,days; はこうなります。 0x1000 year[不定] 0x1004 month[不定] 0x1008 week[不定] 0x100C days[不定] 並びは、アドレス 変数名[値]です。 あくまで仮想アドレスですので実際には違いますよ。 初期値は不定ですが困るので仮に値を入れておきましょう。 year = 2000; mouth = 1; これで 0x1000 year[2000] 0x1004 month[1] となりました。 で、関数呼び出しです。 getYearMonth(&year,&month); &year,&monthで変数のアドレスである0x1000と0x1004がgetYearMonth関数に渡されます。 じゃあ関数側です。 getYearMonth(int *py,int *pm) int *py,int *pmで変数が宣言されて呼び元からの値が入ります。 0x2000 py[0x1000] 0x2004 pm[0x1004] となります。 で scanf("%d %d",py,pm); ですが、pyの中身の0x1000、pmの中身の0x1004がscanf関数に渡されます。 すると scanf("%d %d",&year,&month); の場合、&yearだとyearのアドレス0x1000ですからpyと同じですね。monthも同様です。 整理すると式中の&は変数のアドレスを意味します。&yaerは変数のアドレス0x1000です。 式中の*はアドレスの指す変数そのものですので、*pyは変数そのものです。この例でscanf直前の状態だと2000と言う値です。 宣言中の*はポインタ変数であることを宣言します。int *py;など。

ForceFeed
質問者

補足

>int *py,int *pmで変数が宣言されて呼び元からの値が入ります。 >0x2000 ←ここの所 py[0x1000] >0x2004←ここの所  pm[0x1004] *pyも*pmもyearやmonthの宣言と同じように、アドレスを入れる箱が作られて'*'がなくなるとpy,pmがyearとmonthのアドレスにかわるんですね。

その他の回答 (1)

  • chie65535
  • ベストアンサー率43% (8514/19356)
回答No.2

まず第一に「scanfにはポインタ(アドレス)を渡す」ってのが1つ。 例えば int main() { int year,month,week,days;       : scanf("%d %d",&year,&month); ←scanfにはポインタ(アドレス)を渡す       : return 0; } って書かないといけないって事は理解出来てるよね? んじゃ int main() { int year,month,week,days; int *py,*pm; py = &year; pm = &month       : scanf("%d %d",py,pm); ←scanfにはポインタ(アドレス)を渡す       : return 0; } は? 『「py」と「&year」は同じもの』だよね?代入してんだから同じじゃなきゃ困る。 だったら「py」って書く代わりに「&year」って書いても同じ。それに従って書き替えたら int main() { int year,month,week,days; int *py,*pm; py = &year; pm = &month       : scanf("%d %d",&year,&month); ←scanfにはポインタ(アドレス)を渡す       : return 0; } って感じで、最初のに戻ってしまう。 ここまでは判ってると思う。 んじゃ、scanfに無理矢理に「&」を付けた引数を書いたらどうなるだろう? 『「*py」と「year」は同じ物』って事は判ると思う。 『「*py」と「year」は同じ物』なら、両方に「&」を付けても同じ物のはずだから『「&*py」と「&year」は同じ物』になる。 つまり scanf("%d %d",&year,&month); ←scanfにはポインタ(アドレス)を渡す って書く代わりに scanf("%d %d",&*py,&*pm); ←scanfにはポインタ(アドレス)を渡す って書ける事になる。 なので scanf("%d %d",py,pm); ←scanfにはポインタ(アドレス)を渡す scanf("%d %d",&year,&month); ←scanfにはポインタ(アドレス)を渡す scanf("%d %d",&*py,&*pm); ←scanfにはポインタ(アドレス)を渡す は、全部同じ事をするって事。 つまり >scanf("%d %d",py,pm); //*ここがちょっとわからないところです* って書いてあるのは ≫scanf("%d %d",&*py,&*pm); //*ここがちょっとわからないところです* って書いてあるのと同じな訳。 とゆわけで ≫scanf("%d %d",&(*py),&(*pm)); //*ここがちょっとわからないところです* ≫if((*pm>=1)&&(*pm<=12)){ //1から12月まででそれ以外の数字なら の「*py」を「♪」に、「*pm」を「△」に置き換えれば ≫scanf("%d %d",&♪,&△); //*ここがちょっとわからないところです* ≫if((△>=1)&&(△<=12)){ //1から12月まででそれ以外の数字なら になる。これを「♪」を「year」に、「△」を「month」に置き換え直すと ≫scanf("%d %d",&year,&month); //*ここがちょっとわからないところです* ≫if((month>=1)&&(month<=12)){ //1から12月まででそれ以外の数字なら に戻る。これだと「いつもの見慣れたパターン」だよね?scanfに「&」ちゃんと付けて呼んでる形になったよね。 「&の有る無し」「*の有る無し」で悩んだら『「*pm」を「♪」に置き換える』みたいに「単純化」してみると良い。 以下、まとめ。 重要なのは 「*は、ポインタ変数の中身」 と 「&は、何かのポインタ」 の2つ。 例えれば 「*は『箱の中身』」 と 「&は『中身の箱』」 って感じ。 なので「py」を「箱」と考えれば「&*py」は「【箱の中身】の箱」なので、結局は「単なる箱」って事だから「py」とだけ書いたのと同じになる。 つまり「py」イコール「&*py」って事。 &と*は「互いに、逆の事をする」ので「&*ほげほげ」って感じで2つ繋げると「ほげほげ」だけ、になっちゃう。 あとは「関数の引数にした時はどうなるのか?」だけど、これも『「♪」に置き換え式』で考えればOK。

ForceFeed
質問者

お礼

遅ればせながらでわありますが、その節はありがとうございました。 おかげで、ポインタは自分なりに消化できるようになりました。

ForceFeed
質問者

補足

お二人の説明でscanf()関数で普通の変数に'&'を入れるところが、ポインタ変数の場合はなぜ'&'無しなのか、よくわかりました。 「*は『箱の中身』」と「&は『中身の箱』」はイメージとして わかりやすかったです。

関連するQ&A

  • エラー処理

    万年カレンダーを作っています。 while(1){ printf(" 西暦年>"); scanf("%d",&year); /*西暦年入力*/ printf("   月>"); scanf("%d",&month); /*月入力*/ if(year>0 && month>0 && month<13){     break; } else{ printf("正しく入力してください\n"); } 上記のように、数字のエラー処理をしたのですが、これに数字以外のモノが入力された場合のエラー処理も追加しなければなりません。

  • ポインタいついて教えてください

    ポインタがわかりません。 教えてください。 下の二つは、共に「100」を表記すると思いますが、 どこがどのように違うのですか。 また、f1()という関数をつくって、ここで scanfを使って、5つぐらい値を代入させて、 他の関数でこの値を使おうと思っています。 この場合下のどちらを使うのが、よろしいのでしょうか。 よろしくお願いします #include <stdio.h> int main(void) { int *p, q; q = 100; /* q に100を代入 */ p = &q; /* p にq のアドレスを割り当てる */ printf("%d", *p); return 0; } #include <stdio.h> int main(void) { int *p, q; p = &q; /* q のアドレスを得る */ *p = 100; /* ポインタを使ってq に値を代入する */ printf("%d", q); return 0; }

  • これまた初歩的なことかもしれませんが^^;

    Cです。今作成中の、カレンダーを表示させるプログラムの一部なのですが、それを以下に書きます。 ――――――――――――――― int day_of_week(int year, int month, int day) { int a, i, days1 = 0, days2 = 0, alldays, wk; a = (year - 1)/4; days1 = a * 366 + (year - 1 - a)*365 - (year - 1)/100 + (year - 1)/400; for(i=1; i< month ; i++) days2 += day_of_month(year, i); alldays = days1 + days2 + day; wk = alldays % 7; return(wk); } int write_cal(int year, int month) { /* !!! */ } ――――――――――― 関数write_calで、関数day_of_weekの戻り値wkをつかいたいのですが、!!! にそのままday_of_week(int year, int month, int day)を入れると当然コンパイルエラーになります。初歩的なことをわすれているのかもしれませんが、ポインタなどもつかっていいのでやりかた教えてください! int write_cal(int year, int month, int day) にするというのはナシでお願いします

  • カレンダー作成

    C言語初心者です。 西暦と月を入力してその月のカレンダーを作成するプログラムの問題なのですが #include <stdio.h> #define MMAX 12 #define COMP (year - 1) int main(void) {  int i, j, year, month, day, youbi, ycnt, mcnt = 0;  int mday[MMAX] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};  printf("西暦と月を入力して下さい-->");  scanf("%4d%2d, &year, &month");  if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)   mday[1] = 29;  for (i = 0; i < [A]; i++) {   mcnt += mday[i];  }  mcnt++;  [B] = ((COMP + COMP / 4 - COMP / 100 + COMP / 400) + mcnt) % 7;  printf("\n%4d 年%2d 月\n", year, month);  printf("----------------------------\n");  printf(" 日 月 火 水 木 金 土\n");  for (j = 0, ycnt = 0; j < youbi; j++, ycnt++) {   printf(" ");  }  for (day =1; day <= mday[month - 1]; day++) {   if ([C])    printf("[%2d]", day);   else    printf(" %2d ", day);   ycnt++;   if ([D]) {    printf("\n");    ycnt = 0;   }  }  return (0); } [A]、[B]、[C]、[D]に答えを入れなきゃいけないのですが私が考えた答えだと カレンダーの表示すらされません。どこがいけないのでしょうか? #include <stdio.h> #define MMAX 12 #define COMP (year - 1) int main(void) {  int i, j, year, month, day, youbi, ycnt, mcnt = 0;  int mday[MMAX] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};  printf("西暦と月を入力して下さい-->");  scanf("%4d%2d, &year, &month");  if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)   mday[1] = 29;  for (i = 0; i < month; i++) {   mcnt += mday[i];  }  mcnt++;  youbi = ((COMP + COMP / 4 - COMP / 100 + COMP / 400) + mcnt) % 7;  printf("\n%4d 年%2d 月\n", year, month);  printf("----------------------------\n");  printf(" 日 月 火 水 木 金 土\n");  for (j = 0, ycnt = 0; j < youbi; j++, ycnt++) {   printf(" ");  }  for (day =1; day <= mday[month - 1]; day++) {   if (youbi = 0)    printf("[%2d]", day);   else    printf(" %2d ", day);   ycnt++;   if (youbi > 7) {    printf("\n");    ycnt = 0;   }  }  return (0); } よろしくお願いします。

  • C言語で分からないところがあるのですが……

    C言語で分からないところがあるのですが…… すみません。C言語を学習していてつまづいたので、皆さんの意見を聞きたいと思います。 現在、カレンダーを表示するプログラムをつくっています。 Yearとmonthをユーザが入力すると、その年その月のカレンダーが出るという算段です。(画像貼っておきます。ソースコードは下) これはできました。 これをいじって、Yearをユーザから受け取ると、その年の1月から12月までのカレンダーがば~っと表示されるようにしろ、と言われました。 Yearとmonthを受け取って書くやつは友人の助けを得ながらなんとかかけましたが、もう無理です。多分、for文を使うんだと思うんですが……助けてください! #include <stdio.h> int dayofweek(int year, int month); int daysinmonth(int year, int month); int daysinyear(int year); void showcal(int dow, int days); int main(void) { int year, month; int dow; int dim; printf ("Year?: "); scanf ("%d", &year); printf ("Month?: "); scanf ("%d", &month); dow = dayofweek(year, month); dim = daysinmonth(year, month); showcal(dow, dim); return 0; } void showcal (int dow, int days) { int i, j, d; printf ("Su Mo Tu We Th Fr Sa\n"); d = 1; for (i = 0; i < dow; i++) { printf (" "); } for (; i < 7; i++) { printf (" %d ", d); d++; } printf("\n"); for (j = 0; d <= days; j++) { for (i = 0; i < 7 && d <= days; i++) { if (d < 10) printf (" %d ", d); else printf ("%d ", d); d++; } printf("\n"); } } int daysinmonth( int year, int month) { int dim; dim = 31; if (month == 4 || month == 6 || month == 9 || month == 11) dim = 30; if (month == 2) { if ( (year % 4 == 0 && year % 100 != 0) || year % 400 == 0) dim = 29; else dim = 28; } return dim; } int daysinyear( int year) { int diy; if ( (year % 4 == 0 && year % 100 != 0) || year % 400 == 0) diy = 366; else diy = 365; return diy; } int dayofweek (int year, int month) { int dow; int days; int y, m; if (year >= 2000) { days = 0; for ( y = 2000; y < year; y++ ) { days = days + daysinyear(y); } for ( m = 1; m < month; m++ ) { days = days + daysinmonth(year, m); } dow = (6 + days) % 7; } else { days = 0; for ( m = month; m <= 12; m++ ) { days = days + daysinmo

  • C言語のポインタについて教えてください。

    C言語のポインタについて教えてください。 ・pointer1.c  int main(){   int a;   int *p;   p = &a;     a = 123;   printf("%d", *p);   return 0;  } ・pointer2.c   int main(){ int a[100]; int *p; p = &a[0]; int i; for(i = 0; i < 100; i++) a[i] = i; for(i = 0; i < 100; i++) printf("%d", *p++); return 0; } と二つのソースコードがあるとき、pointer2.cの「p = &a[0]」をpointer1.cのように「p = &a」と書けないのはなぜですか?  また、「&a」は動かすことのできなく、「aを指し示す*p」は動かすことができる変数のようなもの、という認識に誤りはないでしょうか?  宜しくお願いします。

  • 西暦・月からカレンダーを表示

    問題文 西暦・月を入力してカレンダーを表示するプログラムを作成せよ。 プログラム全体のことを考える。プログラムの流れとしては、つぎのようになるであろう。  (1)変数の宣言: プログラムの中で使う変数や配列等をすべてここに集めておく。          (2)入力: キーボードから、西暦年の値を読み取る ← scanf( ) 関数  1月から12月まで、以下を繰り返す。  (3)カレンダーの年・月の表示: (例えば、2008年1月 と表示)  (4)各曜日名の表示: 「日 月 火 水 木 金 土」と表示  (5)月の日数の算出: 月の最後の日を計算しておく。(*1~12月以外では誤りとすること)  (6)曜日の算出: 月の初めの日(ついたち)の曜日をツェラー公式で計算しておく。  (7)空列の表示: ついたちの前の空白部分を表示する ← for文 を利用。  (8)各日の表示: 月の各日を順に表示していく ← for文を利用          (土曜の後に改行を入れる) #include <stdio.h> int leapYear(int year) { if (year%400==0||(year%4==0 && year%100!=0)) { return 1; } else { return 0; } } int main(void) { int d,year,m,i; int day[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; /*1~12月までの各月の日数*/ printf("西暦を入力してください:"); scanf("%d",&year); printf("月を入力してください:"); scanf("%d",&m); if(m!=1 & m!=2 & m!=3 & m!=4 & m!=5 & m!=6 & m!=7 & m!=8 & m!=9 & m!=10 & m!=11 & m!=12)/*1~12月以外で日数を出そうとした場合*/ { printf("入力が誤っています。やりなおしてください。\n"); } else{ if (leapYear(year)==1)/*閏年の場合*/ { printf("%d年は閏年です。\n",year); day[1] +=1; } else/*閏年でない場合*/ { printf("%d年は閏年ではありません。\n",year); } i = (year+year/4 -year/100 +year/400 + ( 13*m+8 )/5 + 1) % 7; /*西暦~年・1~12月の1日の曜日について考える*/ printf("日 月 火 水 木 金 土\n"); (7)・・・ (8)・・・ } return 0; } 手順に沿ってやっていく課題なのですが(7)、(8)の部分の表現の仕方が良く分かりません。(求めた月の日数をカレンダー形式に表示する方法・1日の前に空白を入れる等) 過去の質問も見たのですが、いまいち理解できず・・・orz どなたかご教授お願いできないでしょうか・・・。

  • Cのポインタについて(関数への値渡し)

    C言語のポインタに関する質問です。関数に引数を渡す方法として以下の誤ったswap関数でなぜだめなのかいまいち得心できません。わかりやすくかみくだいて説明していただけると有り難いです。 できましたら、トレースともうしますか、変数の値の動きを詳細に段階的にプログラムの流れに沿って追っていって、だからこうなんだよ、みたいな解説がいただけたら有り難いです。わがままいってすみません。 /* 誤ったswap関数の宣言 */ void swap(int x, int y); int main(void) { int num1 = 5; int num2 = 10; printf("変数num1の値は%dです。¥n", num1); printf("変数num2の値は%dです。¥n", num2); printf("変数num1とnum2の値を交換します。¥n", num1); swap(num1, num2); printf("変数num1の値は%dです。¥n", num1); printf("変数num2の値は%dです。¥n", num2); return 0; } /* 誤ったswap関数の定義 */ void swap(int x, int y) { int tmp; tmp = x; x = y; y = tmp; } ---------- /* swap関数の宣言 */ void swap(int *pX, int *pY); int main(void) { int num1 = 5; int num2 = 10; printf("変数num1の値は%dです。¥n", num1); printf("変数num2の値は%dです。¥n", num2); printf("変数num1とnum2の値を交換します。¥n", num1); swap(&num1, &num2); printf("変数num1の値は%dです。¥n", num1); printf("変数num2の値は%dです。¥n", num2); return 0; } /* swap関数の定義 */ void swap(int *pX, int *pY) { int tmp; tmp = *pX; *pX = *pY; *pY = tmp; }

  • 構造体の自作関数内で入力した値の返し方

    こんばんはm(_ _)m C言語の構造体に関する質問です。 (当方初心者なので用語等見苦しい点があると思いますがご了承&指摘をお願いします。) 日付を元号に直したりする構造体のプログラムでmain関数ではなく自作関数内で値を入力する問題を解いていまして… #include<stdio.h> typedef struct{ int year; int month; int day; }date; date put_date(date x) /*ここで日付を入力*/ { date x;       printf("年:"); scanf("%d",x.year); printf("月:″); scanf("%d",x.month); printf("日:"); scanf("%d",x.day); return x; } int main(void) { date x; x.year=0; /*問題では関数外で宣言した変数では足りないため         に他の自作関数で変数を使いまわすために必要な処         理で初期化しました。*/ put_date(x);     gen(x); /*西暦の日付を元号で表す自作関数でここへput_date        で取得したx,y,zを送りたいのですがmainに来た時点        でput_dataで入力した値が出ませんでした。(元号に        直す関数は省略いたしました)*/ } put_date内でprintfしましたところx,y,zの値が入力した通りに出ましたが、main内ではx.year=0,x.month=12,x.day=0という値になってしまいます。 put_dateで入力した値をmain関数内だけでなく他の自作関数内でも使用したいのですがどうすればよろしいでしょうか?

  • ポインタについて

    下記プログラムはどういう動きをしているのでしょうか。 「printf("&a\t--> %p\n", &a );」は、なぜ「&a」なのでしょうか。 aはポインタ変数として宣言してあるのだから、アドレスを表す場合、「a」ではないのでしょうか。 「a = &value;」でvalueのアドレスをaに受け渡していると思うのですが、この場合、1つのアドレスを複数の変数が指しているということでしょうか。 aの値を25に書き換えれば、valueの値も25になるのでしょうか。 では逆にvalueの値を30に書き換えれば、aの値も30になるのでしょうか。 #include <stdio.h> int main() { int value = 10; int *a; printf("&value\t--> %p\n", &value); printf("&a\t--> %p\n", &a ); a = &value; printf("*a\t--> %d\n", *a ); *a = 25; printf("value \t--> %d\n", value ); return 0; }

専門家に質問してみよう