基本的なconstについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
zxc

基本的なconstについて

#1

投稿記事 by zxc » 7年前

  constの特性を知ろうと初歩的なプログラムを組んだのですが
変換により修飾詞が失われるとC2440のエラーが出てしまいます。
vc++2008 Express Edition で書いております。

コード:

#include<stdio.h>

int main(){
	int  const num = 5;
//	int *const num_point = &num;

	int a = num;
//	int arra[5] = {0,11,22,33,44};

//	num =num+5;//const修飾されているからError
//	num_point++;//const修飾されているからError
	a++;//定数を代入されたものは定数ではない。


//	int i;
//	for( i=0; i<5; i++){
//		printf("%d,%d\n",arra[i],&arra[i]);
//	}

	printf("\na = %d\n&a = %d\n",a,&a);
	printf("num = %d\n&num = %d\n",num,&num);

//	printf("\nnum_point = %d\n\n",num_point);


return 0;
}
  試行錯誤を繰り返した結果このようになりました。
最も上のコメントアウトを外した場合、上に書いたエラーが起こります。
numとnum_pointの両方をconstで修飾することはできないのでしょうか?

 ポインタだろうと何だろうとint型の変数をconstで修飾し、
その後に値を代入してプロンプトで表示させるだけのつもりなのですが
実際には期待通りに動きません。
  それはなぜなのでしょうか?ご指導願います。


 変数num_pointはconst修飾されたnumのポインタの変数のつもりです。
変数aはconst修飾された変数を代入に使えるか試したものです。

アバター
パコネコ
記事: 139
登録日時: 9年前
住所: 大阪

Re: 基本的なconstについて

#2

投稿記事 by パコネコ » 7年前

行いたいことなのかはわかりませんが、

const int *a;
int const *a;

int *const a;

これらの違いはわかりますでしょうか?
(まぁ私も微妙ですが・・・)

こちらで、説明されている内容が参考になるかもしれません。
参照: http://homepage2.nifty.com/tsugu/sotuken/const/


//////////////////////////追記
まったくもって関係ないこといっちゃってましたね・・・
すいませんでした。
最後に編集したユーザー パコネコ on 2012年3月31日(土) 17:56 [ 編集 1 回目 ]
ニャン!!\(゜ロ\)(/ロ゜)/

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 基本的なconstについて

#3

投稿記事 by softya(ソフト屋) » 7年前

const int *const num_point = &num;と書く必要があります。
int const numのポインタを持つ訳ですからね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

zxc

Re: 基本的なconstについて

#4

投稿記事 by zxc » 7年前

  ポインタとconstは二つあわせると複雑になりますね。
パコネコさんの書かれた内容で試していないパターンがあったので
確かめてみましたが解決には至りませんでした。
どうしてこうなるんでしょう。
一応コードを乗せます。

コード:

#include<stdio.h>
int main(){
        int a = 10;
//	int  const num = 5;//変数を定数にする

//	int *const num = &a;//ポインタが定数
//	const *int num = &a;//複数のError!

//  	int const* num = &a; //ポインタも参照先も定数にならない!
//	const int* num = &a;//参照先が定数になる


    return 0;
}
 softya(ソフト屋) さんの書かれたとおりにした場合、Errorが
起こることなくnum_pointが定数になることを確認しました。
理由は今のところわかりませんが、一応解決とします。
コードも張ります。

コード:

#include<stdio.h>
 
int main(){
 
	int  const num = 5;//変数を定数にする
	const int *const num_point = &num;//定数を格納した変数のポインタを定数にとる
 
return 0;
}
 とりあえずconstの定義を調べようと思います。
ご指導いただきありがとうございました。

zxc

Re: 基本的なconstについて

#5

投稿記事 by zxc » 7年前

  解決を押し忘れていました。申し訳ありません。

beatle
記事: 1280
登録日時: 8年前
住所: 埼玉
連絡を取る:

Re: 基本的なconstについて

#6

投稿記事 by beatle » 7年前

一応説明を書いておきます。

const int * a;
int const * a;

と書きますと、「指し示している先」の変更が禁止になりますが、a自体はconstではないので、他のポインタを代入できます。

例えば文字列リテラル"foo"は変更してはいけませんから、
const char * str = "foo";
とするわけですね。こうすれば、strが指し示している先は変更できません。
str[0] = 'a'; // これはエラー

しかしstr自体はconstではありませんから、後から
str = "bar";
などとできます。

これに対し、
int * const b;
と書きますと、bが指し示している先は変更可能ですが、b自体がconstになります。

コード:

int i = 0, j = 0;
int * const ptr = &i;

*ptr = 1; // OK
ptr = &j; // ERROR

beatle
記事: 1280
登録日時: 8年前
住所: 埼玉
連絡を取る:

Re: 基本的なconstについて

#7

投稿記事 by beatle » 7年前

以上のことを組み合わせるとconstが2回登場する変数宣言になり、
「指し示している先を変更することが出来ず、かつ保持しているポインタ値も変更することが出来ない」変数を作ることができます。

コード:

int i = 0, j = 0;
const int * const ptr = &i;

*ptr = 1; // ERROR
ptr = &j; // ERROR

zxc

Re: 基本的なconstについて

#8

投稿記事 by zxc » 7年前

 beatleさんが仰ることはわかった気がします。
二つの宣言を組み合わせたと考えるのですね。
 そう考えると連鎖的にsoftya(ソフト屋)さんの仰ることも
わかったような気がします。

  ポインタのポインタが出たりすると複雑さが増しますね。


  
  これは自分の環境がおかしいのかもしれないのですが、

コード:

const int * a;
int const * a;
  この二つのコードは既に書きましたが、同じ動きをしてくれませんでした。
下のコードはポインタaもその参照先も定数ではない様子でした。

 他のサイトで見る限りポインタでも同一の挙動でありそうだとは思うんですが違いました。
ポインタでなければ同一(に見えます)ですが、皆さんは私とは挙動が違うのですか。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 基本的なconstについて

#9

投稿記事 by softya(ソフト屋) » 7年前

エラーのサンプルです。

コード:

#include<stdio.h>
int main()
{
	int  const num = 5;
	int num2 = 6;
	const int * b;
	int const * c;
	int * const d = &num2;

	b = &num;
	c = &num;
	d = &num2;

	*b = 1;
	*c = 1;
	*d = 1;
	return 0;
}
このサンプルでbとcはint*に対してconstです。つまり同じ意味に解釈されていてポインタ先への代入が出来ません。
dだけは別で変数dがconstです。なので初期値以外はポインタ値を代入できません。

gccでコンパイルした時のエラー。
a.c:13: error: assignment of read-only variable 'd'
a.c:15: error: assignment of read-only location '*b'
a.c:16: error: assignment of read-only location '*c'
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

zxc

Re: 基本的なconstについて

#10

投稿記事 by zxc » 7年前

  softya(ソフト屋)さんのもので示されたエラーと同様のものが出ました。
ということは私が確かめようと組んだプログラムが間違っている
もしくは理解していないということですね。
このプログラムはエラーが出ないのですが、理に適っているのですか?
エラーを出すつもりだったのですが・・・

 コメントアウト部分は挙動が更におかしくなった部分です。
このプログラムを組んでから参照先を定数とすることができなくなったようです。

コード:

#include<stdio.h>

int main(){

	int fig = 12;
	int const* b = &fig;///const int* で通るようにもなってしまいました。////
	printf("%d,%d\n",fig,b);
	fig++;
	b++;
	printf("%d,%d\n",fig,b);

return 0;
}

beatle
記事: 1280
登録日時: 8年前
住所: 埼玉
連絡を取る:

Re: 基本的なconstについて

#11

投稿記事 by beatle » 7年前

変数figがconstか否かは、figの宣言時に決まるのであって、
int const* b = &fig;
と書いたからといって、figがconstになるのではありません。figは常にint型であり、変更可能です。
ただ単に、b経由でfigを書き換えられないだけです。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 基本的なconstについて

#12

投稿記事 by softya(ソフト屋) » 7年前

私が書いたサンプルをもう一度確認してみて下さい。
int const* b = &fig;とconst int*b = &fig;は同じ意味です。
int fig = 12;はconstではないのでfig++;は可能です。
同様に int const* b = &figはint*がconstですのでポインタ先の変更が出来ませんがb++;はポインタ自体の操作ですので変更可能です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

zxc

Re: 基本的なconstについて

#13

投稿記事 by zxc » 7年前

  beatleさんの説明からは、この場合のconstは
「定数化というよりも干渉を制限する」というような印象を受けます。
イメージは幾つかある道の幾つかを塞いでしまう
というものを思い浮かべてます。
  *b = 100; といったようなことでエラーが起きることを確かめたので
一応わかったような気がします。


  softya(ソフト屋) さんの説明からは、
「私の参照・ポインタに関する知識が誤っていた」
というような印象を受けます。

 *bが定数なら当然figも定数だと思ったんですが、違うようですね。
見た目が異なる同一のもの、と認識していましたが
代用可能な別のもの、といった考えの方があっていそうです。

ここでbeatleさんの説明とリンクして
  *bは定数、figは定数でない、だから*bは変化しないが、
figは定数で無いから変化でき、figが変われば連鎖的に
*bの値も変化する、 ということになるんでしょうか。
  つまりconstは四則計算や初期化で無い代入を受け付けない
と言うことになるのでしょうか。

  それとこれは自分が悪いので仕方ないのですが、
他のコードと干渉するのか何かで、同じ書き方でもエラーが
出たり出なかったり結果が安定しないのです。
その結果、

コード:

int const* b = &fig;
const int*b = &fig;
  一応上のコードは同義だとは知ってたつもりでしたが
(定数になるのが何処かは忘れたりしますが。)
今回は同じ動きをしていないように見えたので
コメントアウトという形などで書かせていただきました。
  今後参考にする方がいるのであれば混乱を招きかねない
非常に好ましくないことでした。

  何故安定しないのかわからないと不味いのはわかりますが
constを足しただけで出るなんて理由がわかりません。
解決を押してなおずるずると引きずってしまい申し訳ないです。

beatle
記事: 1280
登録日時: 8年前
住所: 埼玉
連絡を取る:

Re: 基本的なconstについて

#14

投稿記事 by beatle » 7年前

zxc さんが書きました:  beatleさんの説明からは、この場合のconstは
「定数化というよりも干渉を制限する」というような印象を受けます。
イメージは幾つかある道の幾つかを塞いでしまう
というものを思い浮かべてます。
理解の仕方は人それぞれでしょうからなんとも言えませんが、僕が考える「変数fooへのconstポインタを作る」ことのイメージは「fooの読み取り専用の道を作る」ということです。
zxc さんが書きました: ここでbeatleさんの説明とリンクして
  *bは定数、figは定数でない、だから*bは変化しないが、
figは定数で無いから変化でき、figが変われば連鎖的に
*bの値も変化する、 ということになるんでしょうか。
  つまりconstは四則計算や初期化で無い代入を受け付けない
と言うことになるのでしょうか。
連鎖的という言葉は少し語弊を招きそうですね。連鎖的というと、figも*bも個別のメモリ領域を持っており、figへの変更を検知し、即座に*bへコピーされる、という印象を、僕は受けました。
そうではなくて、*bはfigそのものです。figを変更すると、それはすなわち*bの変更なのです。

const変数は四則演算には使えますよ。

コード:

int a = 2, b = 3;
const int* pa = &a;
const int* pb = &b;

int ans = *pa + *pb; // ans == 5
*pa, *pbに書き込む操作だけが禁止です。

naohiro19
記事: 256
登録日時: 9年前
住所: 愛知県

Re: 基本的なconstについて

#15

投稿記事 by naohiro19 » 7年前

const int などが登場する場合はtypedef しておくことをオススメします

コード:

typedef const int CONSINT;

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 基本的なconstについて

#16

投稿記事 by softya(ソフト屋) » 7年前

安定しないと言うコードをぜひ見せて欲しいですね。
想定と実際の結果が違うところをコメントで書いておいて欲しいです。

それと文脈でconstは静的な値として扱われる場合と単なるReadOnlyを強要する機能として扱われる場合がありますね。特にc++の場合。
組み込み分野でRAMが少なくて意識的にROMに追いやる場合はちゃんと意識しないとマズイですが、一般パソコンならReadOnlyを強要する機能だと思っていて良いと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

zxc

Re: 基本的なconstについて

#17

投稿記事 by zxc » 7年前

  beatleさんとsoftya(ソフト屋) さんすいませんでした。
コードは上書きしてしまっていたので確かめようも無いですが、
おそらく安定しないと思い込んだ原因はポインタだったのだろうと思います。
そしてconstを良くわかっていないことが悪化を招いたのでしょう。

  (そのあたりの知識がうやむやだったので、対照実験ではないのに
そうであると思い込んでコードを書いた結果、安定しなかったのだろうと思います。
  そのように考えると勘違いの説明がつくようです。)

コード:

#include<stdio.h>

int main(){
	int a = 1;
	const int * b = &a;
	a = 10;

	return 0;
}
  constに関して判らなかったのがこのようなコードで、
私が*bにaを代入して考えていたからです。
  そのため変数aが変化した場合「エラーが出ないのはおかしい」
と大間違いをしでかしたわけです。(*bが定数ならaも同様と思っていたのです。)
  (aの中身へのアクセスが可能な経路が2つあり、一方が
読み取りしかできないわけですよね。DVD-Rに似ている気がします。)


  そこにポインタのこのようなミスが混じってしまったので
余計にわけが判らなくなったんだと思います。実際に詰まったコードではないですが
一応張ります。

  次の場合で言えば*bを変えたのにaが変わらないことと
constで修飾した*bが変化してることが原因です。
 *b(もしくはb)は変わっていけないと思ってますし、変われば
a(もしくは&a)も変わるのではないか、と思うのです。
一応*bにconstがかかっていると思います。bは変わりました。
(これは今もわからないです)

コード:

#include<stdio.h>

int main(){
	int a = 1;
	int const* b = &a;

	printf("a = %d,*b = %d\n",a,*b);
	*b++;//*b = 10;ではerror・・・だからインクリメントがいけない?
	printf("a = %d,*b = %d\n",a,*b);

	return 0;
}
 これにインクリメントがほんのり絡んだりします。
インクリメントで「constで修飾されている」というエラーが出るコードもあれば
「++には左辺が必要」というエラーが出ることも
(この場合、新たに代入を試みるとconstで修飾されている、と言われます。)、
もしくは上のコードのように
定数化したつもりでも数字が変わるコードもある。という3パターンが今までありました。
(いつどのエラーが出るか、何故出るか、わかりません。)

<想定と実際の結果が違うところをコメントで>
 コメントアウトではないですが一応自分が示すべきと思ったことを
今回意識して、できる限り書いたつもりです。

<constは静的な値として扱われる場合と単なるReadOnlyを強要する機能
として扱われる場合があります>
  constが使われる場面も静的・動的のことも詳しく知っているわけではないですが、
staticやローカル変数のように他ファイルから直接使用されない(だったはず・・・)
ようにする目的の場合と
変えたくない値が変わってしまうのを防ぐ目的の二つということですか。

<figも*bも個別のメモリ領域を持っており~>
 そのように考えていました。それが変わり、
ある物を指す矢印が2本存在し、1本が読み取りしかできないといったイメージです。

<const変数は四則演算には使えますよ。>
 そのとおりですよね。何で私はこんなこと書いたんでしょう。
計算する関数の仮引数にconst使えない、ということになってしまいますから・・・

   naohiro19 さん
typedefはこのように使うのが上手な使い方なのですね。
今までの自分の用法よりもすっきりしています。

  面倒をかけて申し訳ありませんが、よろしくお願いします。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: 基本的なconstについて

#18

投稿記事 by softya(ソフト屋) » 7年前

zxc さんが書きました:<constは静的な値として扱われる場合と単なるReadOnlyを強要する機能
として扱われる場合があります>
  constが使われる場面も静的・動的のことも詳しく知っているわけではないですが、
staticやローカル変数のように他ファイルから直接使用されない(だったはず・・・)
ようにする目的の場合と
変えたくない値が変わってしまうのを防ぐ目的の二つということですか。
constを書いたポインタでは無い基本データ型(intやfloat等)は静的な定数(書き換えれない値)と思ってもらって良いです。
それ以外の場合でconstを書いた場合にはReadOnlyを強要する機能と考えてもらって差し支えないと思います。
あとexternを書いてグローバルconstは作れます。

コード:

//hoge.h
extern const int gint;
//hoge.cpp
const int gint = 1;
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

“C言語何でも質問掲示板” へ戻る