Cでソケット通信などはできるくらい(もちろんできると言っても私のレベルで)
になりましたが、文字列を宣言する際に
char *str = "ahaha';
char str[] = "ahaha";
の2種類の違いが今イチしっくりきません。
いろんな参考書でこれの説明はありましたが、でも結局なんなんだ、という感じです。
ポインタで宣言するべき時、配列で宣言するべきときが判断できません。
またポインタで宣言するとエラーが出るけど試し配列で宣言してみたら
なんか知らんが動いた、ということも多々ありましたが理由がよくわからなかったです。
よろしくお願いいたします。
No.9
- 回答日時:
>char *strもあればchar str[]もありますが
>べつにどちらか片方あればいいんじゃないでしょうか。
これは私の思い込みですが、
この2つはC言語で実装する方法が同じだけであって、
用途としては使い分けるのが正しいと思います。
つまりC言語がこれらの変換を暗黙で行っていたとしても
ポインタ変数は、変数の「アドレスを代入できる変数」であり、
配列名は複数の変数の先頭を示すアドレス「複数の変数」です。
違いと言うものは存在していると思います。
No.8
- 回答日時:
プログラム実行時にコードが置かれるメモリは書き換えられるとプログラムが動かなくなるので読み込み専用として保護されます。
この領域に書き込みしようとするとaccess violationのエラーが出て異常終了になります。
char *str = "ahaha';
の場合のポインタはこの書き込み禁止領域のアドレスになるということです。
char str[] = "ahaha";
の場合は読み書き自由なエリアのアドレスになります。
No.7ベストアンサー
- 回答日時:
#1、#2の方のとおり、
char *str = "ahaha'; は書き換え不可能な文字列
char str[] = "ahaaha"; は書き換え可能な文字列
っていう違いです。
パソコンのユーザーアプリなんかでは、普通書き換え可能なRAMにしかアクセスできないんで、あんまり違いはないんですが。
小さなメモリ+ROMみたいな組み込みのシステムでは、
char *str = "ahaha';
は、固定文字列(書き換え不可能)で、多くの場合ROMに置かれます。
char str[] = "ahaha';
は、書き換え可能ですから、ROMには置けず、RAMに置かないといけません。(必ずしもスタックに置く必要はないですが)
No.6
- 回答日時:
>ただわざわざ2種類用意されている必然性って何なのでしょうか。
>いろんなソースを見ていると
>char *strもあればchar str[]もありますが
>べつにどちらか片方あればいいんじゃないでしょうか。
char str[] = "ahaaha";
が許されないと、文字配列 str の初期化をいちいちループをまわして(あるいは strncpy で)書かねばならず、面倒なので却下。
char *str = "ahaaha";
が許されないと。。。思い付かん。
多分 char str[] で代替可能だけど、ただのポインタの初期化だから、これだけ禁止にする理由もなかろう。
一つのソースの中で使い方が統一されていれば、特に問題ないと思われますが。
私は大抵前者を変更され得る文字配列の初期化に、後者をマジックナンバーを回避するための定数変数の宣言に使っています。
No.5
- 回答日時:
あと、そういえば
Ano.3 の図にもありますが
* だと
str見て -> アドレス書いてあった。
アドレス見て -> "ahaha" って書いてあった。
の2回メモリアクセス
[] だと
"ahaha" って書いてあった
の1回アクセス
ですね。
最適化されるとそうなるか分からないですが。
なんかださっきの結論と逆ですが、違いがでる場所が違うので気にしないで下さい。(無責任)
結論としては、出来たプログラムを逆アセンブルしてみると面白いかもしれません。
多分、どの本にも書いてない事が分かりますよ。(見るときの気持ち次第ですが)
No.4
- 回答日時:
多分どっちでも、目的のプログラムは書けるんじゃないかと思います。
その他思う事としては、
str が どこかの関数のローカル変数なら
[] の方は、関数に入る度に スタックに
0x61 0x68 0x61 0x68 0x61 0x00 => "ahaha"
と書かないといけないので、ちょっと遅いかもしれません。
(x86のcpuなら 0x68616861 と 0x0061 の2回のアクセスかなぁ?)
ただ同様に、
* の場合は、スタックに "ahaha" のアドレスを書かないとダメなの
これにも時間がかかります。
(こっちはアドレスなので 32bits 1回)
まとめると もっと 文字数が多いと差が出るんじゃないかと思います。
あと
> いろんな参考書でこれの説明はありましたが、でも結局なんなんだ、という感じです。
こういう気持はすごく良く分かります。
結局、本って他人が過去に思った疑問に答えてるような部分があるので
自分の疑問には答えてくれませんよね。
No.3
- 回答日時:
●char *str = "ahaha";
┌──┐ ┌─┬─┬─┬─┬─┬─┐
str│ ・─┼─→│_a_│_h_│_a_│_h_│_a_│_\0_│
└──┘ └─┴─┴─┴─┴─┴─┘
●char str[] = "ahaha";
┌─┬─┬─┬─┬─┬─┐
str│_a_│_h_│_a_│_h_│_a_│_\0_│
└─┴─┴─┴─┴─┴─┘
みなさんありがとうございます。
ただみなさんのおっしゃっているあたりのことは私も大体理解できているのです。
(すみません、初めに言っておくべきでした。)
ただわざわざ2種類用意されている必然性って何なのでしょうか。
いろんなソースを見ていると
char *strもあればchar str[]もありますが
べつにどちらか片方あればいいんじゃないでしょうか。
あるソースでchar *strと宣言した方は何故char str[]じゃ嫌だったんでしょう。
逆もまた然りです。
No.2
- 回答日時:
int main(void)
{
char* str = "aaa";
char str2[] = "bbb";
//*str = 'c';
*str2 = 'd';
printf( "%s\n", str );
printf( "%s\n", str2 );
return 0;
}
上記のプログラムで、
strは文字リテラルへのポインタになります。
つまり。
「リテラル」つまり「定数」です
何処かの領域[0] = 'a'
何処かの領域[1] = 'a'
何処かの領域[2] = 'a'
何処かの領域[3] = '\0'
str = 何処かの領域のアドレス
str2は、(文字列の)配列変数です。
str2[0] = 'b'
str2[1] = 'b'
str2[2] = 'b'
str2[3] = '\0'
上記のプログラムで、
*str = 'c';
とできないのは、「定数」であるstrの
先の領域を書き換えようとしている為です。
C++などではこれをDefineの代わりに使用します。
const char* PATH = "c:\tmp\path";
No.1
- 回答日時:
char* str = "ahaaha";
は「どこかの静的な領域に取られた」"ahaaha" にアクセスするために、そのアドレスを str に格納している。
当然、str の指す場所には書き込めない。本来 const char* と宣言するべき
char str[] = "ahaaha";
は「自分で確保したスタック領域」を "ahaaha" で初期化。
もちろん、後で str を書換えることも可能。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語 コマンドライン引数 4 2023/02/09 18:47
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# c言語 配列とポインタについて 3 2023/02/09 22:53
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- 政治 気象庁の「梅雨明け宣言」は不要。 14 2023/07/11 13:15
- C言語・C++・C# C言語の質問です。 以下の命令を実行するプログラムを作りました ①文字列aとbの長さを表示 ②aとb 1 2022/04/29 15:35
- C言語・C++・C# C言語 ポインタ 配列 2 2022/06/02 17:29
- C言語・C++・C# 関数ポインタの高速化のメリット 7 2023/05/05 20:15
- C言語・C++・C# str[j++]の意味 2 2022/08/30 16:20
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語にて構造体のメンバがNULL...
-
char*を初期化したいのですが
-
コマンドライン引数 *argv[]は...
-
C言語のintとcharの違いってな...
-
char 文字列型 の表現範囲が-12...
-
CStringからchar*への型変換に...
-
小数点入りの文字列をfloat型に...
-
エクセルのMID関数は、C言語では?
-
ポインタを使用 [数字列を数値...
-
C言語:小文字を大文字に変換す...
-
文字列のswap
-
WritePrivateProfileString
-
csvファイルをfscanfで読み込む...
-
WM_CHAR or WM_KEYDOWN の「wPa...
-
char AA[]{"全角文字"};から"全...
-
fstream型オブジェクトを関数の...
-
文字列str内の全ての数字を...
-
const char* s1とただのchar s1...
-
C言語で文字列をかえす正しい書...
-
動的メモリの初期化方法について。
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
char*を初期化したいのですが
-
C言語のintとcharの違いってな...
-
CStringからchar*への型変換に...
-
C言語にて構造体のメンバがNULL...
-
小数点入りの文字列をfloat型に...
-
C言語のプログラムについてです
-
strcat関数を自作したいです
-
fstream型オブジェクトを関数の...
-
new charとnew char[N]の違いは?
-
DWORDとcharの変換
-
文字列の途中から途中までを抽出
-
char 文字列型 の表現範囲が-12...
-
const char* s1とただのchar s1...
-
wsprintf( ポインタ , "%d" , "...
-
c言語でポインタ変数を用いた配...
-
char型にint型の数値を代入する。
-
C言語で文字列をかえす正しい書...
-
C++17で、unsigned char * 配列...
-
共用体について
-
エクセルのMID関数は、C言語では?
おすすめ情報