C言語で以下のようなソースを作成したのですが
一点疑問がでてきました。
C
1#include <stdio.h> 2#include <stdlib.h> 3 4 5 6int main (int argument_count, char *argument_string[]) { 7 8 char *path; 9 for (int i = 0; i < argument_count; i++) { 10 path = argument_string[i]; 11 printf("%s", path); 12 } 13 return 0; 14} 15
上記のようにコンパイル後に上記バイナリを実行時,
コマンドライン引数を char *path と宣言された pathという変数にコマンド引数を代入して
出力していますが,この時ポインタ変数のメモリ確保を行っていないのですが,windowsのコマンドプロンプト上では
問題なくコマンドライン引数が出力されてしましました。
疑問点は ポインタ変数は初期化せずに動的にどのようなバイト数の文字列も格納できるのでしょうか?
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答5件
0
ポインタ変数は初期化せずに動的にどのようなバイト数の文字列も格納できるのでしょうか?
は、間違っています。ポインタ変数に文字列はどんなものであっても格納できません。
ポインタ変数には、どのようなバイト数の文字列を指すポインタも格納できる
というのが正しいです。
なので、そのプログラムは正常に動きます。
投稿2017/07/25 14:40
総合スコア84557
0
ベストアンサー
どうもC初心者あるあるネタの配列とポインタと文字列がごっちゃになっているパターンかと思われますね。
配列
配列とはある一つの型のデータが任意個数連続して並んでいる領域のことです。
c
1int arr[3];//int型のデータが3個連続して並んでいる領域
配列型の重要な性質として、式中では3つの例外を除き配列型はつねにポインタ型に読み替えられると言うものがあります。つまり配列のある領域をさすポインタとして解釈されるということです。
c
1int arr[3]; 2arr;//arrはint[3]型なんだけどint*型として解釈される 3sizeof(arr);//sizof演算子は3つの例外の一つ
文字列リテラル
c
1"arikitari";//char配列型、処理系依存の型 2u8"ありきたりなせかい";//const char[28]型 3L"????";//wchar_t配列型、処理系依存の型 4u"????";//const char16_t[3]型 5U"????";//const char32_t[2]型
こんなやつらです。
([C++11~]const修飾された)配列型になります。
u8
/u
/U
はprefixといって、これがつくと文字列リテラルはそれぞれUTF-8
/UTF-16
/UTF-32
でエンコードされます。
L
もprefixですが、Unicodeのどのエンコードが使われるかは決まっていません。一般にはUTF-16
(Windows)/UTF-32
(Linux)が用いられます。
prefixがついていない文字列リテラルの文字コードは処理系依存です。
要素数は文字エンコードした時のCode units数+1(NULL文字分)になります。
Code unitsについては
http://unicode.org/faq/char_combmark.html#7
を参照してください。
文字列リテラルは配列型なので先に述べたとおり3つの例外を除きポインタ型に読み替えられます。
c
1u8"ありきたりなせかい";//const char[28]型なんだけどconst char*型として扱われる 2const char* str; 3//文字列リテラルはconst char*型として扱われるので、 4//文字列リテラルは文字列が格納された領域へのポインタとして解釈されている。 5//このポインタを変数strに代入しているが、これはポインタのコピー。 6str = u8"ありきたりなせかい";
多くの場合、文字列リテラルはコンパイルしてできた実行ファイル中にエンコード済みの形で埋め込まれ、実行時は読み出し専用のメモリー領域に配置されます。
問題のプログラムを解釈してみる
c
1#include <stdio.h> 2#include <stdlib.h> 3 4//文字列が格納された領域を指すポインタの配列へのポインタが 5//プログラム実行時、main関数が呼ばれる時にargument_stringに渡される 6int main (int argument_count, char *argument_string[]) { 7 8 char *path; 9 for (int i = 0; i < argument_count; i++) { 10 //これはただのポインタのコピー 11 path = argument_string[i]; 12 printf("%s", path); 13 } 14 return 0; 15}
投稿2017/07/26 04:09
総合スコア5850
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ポインタ変数が格納しているのは文字列ではなく、その文字列のアドレスです。
どのような長さの文字列であっても、その先頭のアドレスは一定のサイズで表現可能です。
ですから、ご提示のコードは正しく動作します。
嬉しいことに、有益なコメントを皆様書き込んでくださいました。
そちらも併せてごらんくださいね。
投稿2017/07/25 14:34
編集2017/07/26 03:47総合スコア35660
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/07/25 15:40
2017/07/25 15:50
2017/07/25 17:39
2017/07/25 22:03
2017/07/26 03:28
2017/07/26 03:48
0
C
1char* path;
このようなブロック内での変数宣言は auto 変数といって、宣言された時点でメモリ(あるいはCPUレジスタ)が確保されます。
ただし、確保されたのはポインタ変数であって、そのポインタ変数が示す先については未定義です。
※宣言時点で null に初期化されている場合もあるが、C コンパイラの実装に依存するためそれを期待してはいけません
C
1char* msg = "あいうえお";
これはまず、"あいうえお"というのをメモリのどこかに確保し、そのメモリアドレスを、ポインタ変数に初期値として代入しています。
※実際の"あいうえお"のメモリ部分は、プログラムの実行ファイル内のデータ専用領域に(コンパイルされた時点で)確保され存在しています。ので、プログラムをロードした時点で確保済みです。
つまりこの場合、メモリは2か所(ポインタ変数の分と、その示す先の文字列分)確保されています。
投稿2017/07/26 04:46
総合スコア13703
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。