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

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

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

charは文字データ型を指します。一文字分の文字コードの格納を想定としている型です。

C

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

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

Q&A

解決済

2回答

385閲覧

C言語の文字列の文字数が変数の宣言によって異なる理由

Kchan_01

総合スコア110

char

charは文字データ型を指します。一文字分の文字コードの格納を想定としている型です。

C

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

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

0グッド

0クリップ

投稿2020/02/20 06:03

編集2020/02/20 06:06

C言語を勉強していて変な仕様を見つけました。
charを100文字で宣言した場合と1000文字で宣言した場合で出力される文字数が異なります。
100と101で宣言しても102と100と出力されます。

この現象の理由を知りたいのですが、検索ワードがわからずにモヤモヤしています。
ご存知の方がいらっしゃったら教えていただけますと幸いです。

c

1#include <stdio.h> 2#include <string.h> 3 4int main(void) 5{ 6 char str1[100]="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 7 char str2[1000]="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 8 9 printf("str1は%lu\n", strlen(str1)); 10 printf("str2は%lu\n", strlen(str2)); 11 12 return 0; 13}

terminal

1str1は102 2str2は100

追加でやってみました。同じ文字列を出力させても文字数が変わります。

c

1 char str1[100]="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 2 char str2[100]="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 3 char str3[100]="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 4 char str4[100]="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 5 6 printf("%lu\n", strlen(str1)); 7 printf("%lu\n", strlen(str2)); 8 printf("%lu\n", strlen(str3)); 9 printf("%lu\n", strlen(str4)); 10 return 0;

terminal

1102 2101 3101 4110

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

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

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

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

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

cateye

2020/02/20 06:11

char str1[100]を、100文字で初期化すると“100文字で収まらない”のは理解していますか?
Kchan_01

2020/02/20 06:24

文字の配列の最後に'\0'があることは理解していましたが、 >>末端を超えて読み進めてしまい、メモリのどこかに転がっていた\0までを文字列と認識してしまいます。 ということを理解していませんでした。エラーで弾かれず読み進めるということに驚きです。
guest

回答2

0

ベストアンサー

このaaa...aはちょうど100文字ありますが、char str1[100] = "(aが100文字)";と初期化すると、末端の\0が入りません

末端を超えて読み進めてしまい、メモリのどこかに転がっていた\0までを文字列と認識してしまいます。

投稿2020/02/20 06:05

編集2020/02/20 06:06
maisumakun

総合スコア145201

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

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

Kchan_01

2020/02/20 06:08

あ、だから実行するたびに値が異なるのですね!ありがとうございます!
guest

0

末端を超え…メモリのどこかに転がっていた\0までを文字列と認識
エラーで弾かれず読み進めるということに驚き

こうしてCの文字列の定義を再認識するんですね。「C言語 一皮むけばアセンブラ(るばーと心の俳句)」でして、一般的な言語に比べてより生のメモリを相手にする感がありますから、この機会にメモリをダンプして直接見てみると面白いです。

C

1#include <stdio.h> 2#include <string.h> 3#include <ctype.h> // for isprint() 4void mdump(void *vp, int size, const char *msg); 5int main(void) 6{ 7 char str1[100] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 8 char str2[1000] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 9 printf("str1は%lu\n", strlen(str1)); 10 printf("str2は%lu\n", strlen(str2)); 11 12 printf("str1は%p番地から\n", str1); // str1[]のアドレス 13 printf("str2は%p番地から\n", str2); // str2[]のアドレス 14 mdump(str1, 220, "str1[]"); // str1[] からメモリダンプ 15 return 0; 16} 17 18/*====================================================================== 19Func Name : void mdump(void *vp, int size, const char *msg); 20Function : Dump memory 21Param Input : void *vp = memory address 22 int size = size to be dumped, 16 bytes align 23 char *msg = message to identify memory block 24Param Output, Return, Input Inf, Output Inf : None 25Note : # How to compile with your 'prog.c', 26 # > cc prog.c mdump.c 27Revision : 1.00 2016/05/14 Created by rubato6809 28======================================================================*/ 29#define LINESIZE 16 // 16バイトを一行に表示 30void mdump(void *vp, int size, const char *msg) 31{ 32 unsigned char *mem = vp; // 常に無符号char領域としてアクセス 33 int ltop, lnext; // line-top and line-next 34 35 // 識別メッセージを表示 36 if (msg) printf(" '%s'", msg); // つまり、NULLなら表示しない 37 printf("\n"); // でも最初に改行だけはする 38 39 for (ltop = 0; ltop < size; ltop = lnext) { // LINESIZE 毎に繰返す 40 lnext = ltop + LINESIZE; // 次の行の先頭位置 41 printf("%p: ", &mem[ltop]); // 今の行の先頭アドレス 42 43 for (int i = ltop; i < lnext; i++) // メモリの値を16進数で表示 44 printf("%02x ", mem[i]); 45 46 for (int i = ltop; i < lnext; i++) { // 文字表示、ascii dump 47 unsigned char c = mem[i]; // メモリの値 48 printf("%c", isprint(c) ? c : '.'); // 表示不能なら '.' を 49 } 50 printf("\n"); 51 } 52} 53

私の実行結果はこうです。

bash

1$ ./a.out 2str1は102 3str2は100 4str1は0x7fff0f8b84b0番地から 5str2は0x7fff0f8b8520番地から 6 'str1[]' 70x7fff0f8b84b0: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa 80x7fff0f8b84c0: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa 90x7fff0f8b84d0: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa 100x7fff0f8b84e0: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa 110x7fff0f8b84f0: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa 120x7fff0f8b8500: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa 130x7fff0f8b8510: 61 61 61 61 12 7f 00 00 4b 06 e2 1d 12 7f 00 00 aaaa....K....... 140x7fff0f8b8520: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa 150x7fff0f8b8530: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa 160x7fff0f8b8540: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa 170x7fff0f8b8550: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa 180x7fff0f8b8560: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa 190x7fff0f8b8570: 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa 200x7fff0f8b8580: 61 61 61 61 00 00 00 00 00 00 00 00 00 00 00 00 aaaa............

私の手元の64bit GCCでも「str1は102」と表示するので、質問者も似たような状況だろうと独断して解説を試みます。

0x7fff0f8b8510: 61 61 61 61 12 7f 00 00 4b 06 e2 1d 12 7f 00 00 aaaa....K.......
の表示から

  • 「12 7f 00」の部分が +2 バイトだとわかる
  • 「12 7f 00 00 4b 06 e2 1d 12 7f 00 00」の12バイトは str1[] と str2[] の間に挟まれた隙間部分で、本来は使う予定の無いメモリ
  • 隙間部分を設けた理由は、str2[] を16バイト境界から配置してキャッシュを有効利用したいからだろう
  • 「4b 06 e2 1d 12 7f 00 00」は、十中八九 0x7f121de2064b という値のポインタ変数だった
  • 同様に、+2 バイト分の「12 7f 00 00」もここにポインタ変数があった痕跡だろうetc.

さらに、たとえば

C

1 char str2[1000]; // ="aaaaa...a";

とすれば、str2[1000] は初期化されない 1000 バイトのメモリ領域となり、そこに在る様々な値、いわゆるゴミですが、見ようによっては美しい模様として眺めることができます。このように実際のメモリの姿を見ておくとC言語の仕組みの一端を具体的に実感としてつかむことができ、デバッグにも役立ちます。
Enjoy !

投稿2020/02/21 01:44

編集2020/02/21 03:22
rubato6809

総合スコア1380

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問