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

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

ただいまの
回答率

88.62%

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

解決済

回答 5

投稿

  • 評価
  • クリップ 0
  • VIEW 2,981

jacky

score 45

C言語で以下のようなソースを作成したのですが
一点疑問がでてきました。

#include <stdio.h>
#include <stdlib.h>



int main (int argument_count, char *argument_string[]) {

  char *path;
  for (int i = 0; i < argument_count; i++) {
    path = argument_string[i];
    printf("%s", path);
  }
  return 0;
}

上記のようにコンパイル後に上記バイナリを実行時,
コマンドライン引数を char *path と宣言された pathという変数にコマンド引数を代入して
出力していますが,この時ポインタ変数のメモリ確保を行っていないのですが,windowsのコマンドプロンプト上では
問題なくコマンドライン引数が出力されてしましました。

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

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

+2

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

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

+1

どうもC初心者あるあるネタの配列とポインタと文字列がごっちゃになっているパターンかと思われますね。

 配列

配列とはある一つの型のデータが任意個数連続して並んでいる領域のことです。

int arr[3];//int型のデータが3個連続して並んでいる領域

配列型の重要な性質として、式中では3つの例外を除き配列型はつねにポインタ型に読み替えられると言うものがあります。つまり配列のある領域をさすポインタとして解釈されるということです。

int arr[3];
arr;//arrはint[3]型なんだけどint*型として解釈される
sizeof(arr);//sizof演算子は3つの例外の一つ

 文字列リテラル

"arikitari";//char配列型、処理系依存の型
u8"ありきたりなせかい";//const char[28]型
L"🍣";//wchar_t配列型、処理系依存の型
u"🍺";//const char16_t[3]型
U"🍖";//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つの例外を除きポインタ型に読み替えられます。

u8"ありきたりなせかい";//const char[28]型なんだけどconst char*型として扱われる
const char* str;
//文字列リテラルはconst char*型として扱われるので、
//文字列リテラルは文字列が格納された領域へのポインタとして解釈されている。
//このポインタを変数strに代入しているが、これはポインタのコピー。
str = u8"ありきたりなせかい";

多くの場合、文字列リテラルはコンパイルしてできた実行ファイル中にエンコード済みの形で埋め込まれ、実行時は読み出し専用のメモリー領域に配置されます。

 問題のプログラムを解釈してみる

#include <stdio.h>
#include <stdlib.h>

//文字列が格納された領域を指すポインタの配列へのポインタが
//プログラム実行時、main関数が呼ばれる時にargument_stringに渡される
int main (int argument_count, char *argument_string[]) {

  char *path;
  for (int i = 0; i < argument_count; i++) {
    //これはただのポインタのコピー
    path = argument_string[i];
    printf("%s", path);
  }
  return 0;
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

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


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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/26 07:03

    メモリの図を描くことが、Cでは特に大事なんですよ。
    ふつうの変数・文字列配列・ポインタ変数・ポインタの配列などが、メモリ上でどんな姿をしているか、どれだけのバイト数を必要とするか、どんな配置になるか・・・かなり具体的にイメージできるものなのですが、それが出来るかどうか。この場合も
    path = argument_string[i]; を図に描いてみる。

    プログラムの字面や言葉で理解しようとしても限界がある。少なくとも、理解できるまで時間がかかってしまう。百聞は一見に如かず。

    キャンセル

  • 2017/07/26 12:28

    同じく「メモリの図を描く」ことはC言語を理解する場合はとても良い事です。下記が図解されていて良いかもしれません。
    https://www.grapecity.com/tools/support/powernews/column/clang/028/page02.htm

    キャンセル

  • 2017/07/26 12:48

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

    キャンセル

+1

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

char* path;


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

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


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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 88.62%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る