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

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

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

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

Q&A

解決済

5回答

896閲覧

C言語でchar型のポインタの初期値について

退会済みユーザー

退会済みユーザー

総合スコア0

C

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

0グッド

0クリップ

投稿2017/07/25 14:31

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ページで確認できます。

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

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

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

guest

回答5

0

ポインタ変数は初期化せずに動的にどのようなバイト数の文字列も格納できるのでしょうか?

は、間違っています。ポインタ変数に文字列はどんなものであっても格納できません。

ポインタ変数には、どのようなバイト数の文字列を指すポインタも格納できる

というのが正しいです。
なので、そのプログラムは正常に動きます。

投稿2017/07/25 14:40

otn

総合スコア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

yumetodo

総合スコア5850

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

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

0

mainには、「既に確保され、コマンドラインの内容がコピーされている」argvが渡されます。それを参照するのはもちろん合法です。そしてpathも「初期化していますから」それを参照するのも合法です。

投稿2017/07/25 15:12

majiponi

総合スコア1720

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

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

0

ポインタ変数が格納しているのは文字列ではなく、その文字列のアドレスです。
どのような長さの文字列であっても、その先頭のアドレスは一定のサイズで表現可能です。
ですから、ご提示のコードは正しく動作します。


嬉しいことに、有益なコメントを皆様書き込んでくださいました。
そちらも併せてごらんくださいね。

投稿2017/07/25 14:34

編集2017/07/26 03:47
LouiS0616

総合スコア35660

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

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

退会済みユーザー

退会済みユーザー

2017/07/25 15:36

ご回答ありがとうございます。 >ポインタ変数が格納しているのは文字列ではなく、その文字列のアドレスです。 これって path = argument_string[i]; を path = "あいうえお"; とした場合,この「あいうえお」とは つまり, char s[] = {"文字列"}; printf("%p", &s); // 出力は => 0028FF22 のように出力される「0028FF22」がアドレス値であるように 「あいうえお」もアドレス値と呼べるということなのでしょうか??
LouiS0616

2017/07/25 15:40

いや、”あいうえお”はアドレス値とは呼べません。それはリテラルです。 文字列リテラルをポインタ変数に代入しようとすると、文字列自体ではなく先頭のアドレスが代入されるようになっています。 sizeof演算子を用いて試してみると、どのような長さの文字列でポインタ変数を初期化しても、その変数のサイズが変わらないことがわかります。
LouiS0616

2017/07/25 15:50

あと、ご提示の以下のコードは何か変ですね。 char s[] = {"文字列"}; printf("%p", &s); 文字列の配列を使いたいなら二次元配列を用いるべきです。 そのあとのprintf関数もちょっとあやしいです。
SaitoAtsushi

2017/07/25 17:39

文字列リテラルというのは型で言えばあくまで char の配列なんですが、状況がそろうと勝手にポインタに変換されるんです。 このあたり、 C だと暗黙の型変換でうまいこと処理されちゃうんでどうなってるのかかえって分かり難いんですよね……。
rubato6809

2017/07/25 22:03

メモリの図を描くことが、Cでは特に大事なんですよ。 ふつうの変数・文字列配列・ポインタ変数・ポインタの配列などが、メモリ上でどんな姿をしているか、どれだけのバイト数を必要とするか、どんな配置になるか・・・かなり具体的にイメージできるものなのですが、それが出来るかどうか。この場合も path = argument_string[i]; を図に描いてみる。 プログラムの字面や言葉で理解しようとしても限界がある。少なくとも、理解できるまで時間がかかってしまう。百聞は一見に如かず。
LouiS0616

2017/07/26 03:48

私自身もとても勉強になります。コメントありがとうございます。
guest

0

C

1char* path;

このようなブロック内での変数宣言は auto 変数といって、宣言された時点でメモリ(あるいはCPUレジスタ)が確保されます。
ただし、確保されたのはポインタ変数であって、そのポインタ変数が示す先については未定義です。
※宣言時点で null に初期化されている場合もあるが、C コンパイラの実装に依存するためそれを期待してはいけません

C

1char* msg = "あいうえお";

これはまず、"あいうえお"というのをメモリのどこかに確保し、そのメモリアドレスを、ポインタ変数に初期値として代入しています。
※実際の"あいうえお"のメモリ部分は、プログラムの実行ファイル内のデータ専用領域に(コンパイルされた時点で)確保され存在しています。ので、プログラムをロードした時点で確保済みです。
つまりこの場合、メモリは2か所(ポインタ変数の分と、その示す先の文字列分)確保されています。

投稿2017/07/26 04:46

tacsheaven

総合スコア13703

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問