🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

4回答

1313閲覧

文字列とポインタを扱ったプログラムの疑問。

carnage0216

総合スコア194

C

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2021/02/15 18:14

編集2021/02/15 18:43
#include <stdio.h> int main(void) { char str[] = { "abcde" }; for (char* p = str; *p; ++p) { ++(*p); printf("%s\n", &(*p)); } }
結果は bbcde ccde dde ee f

ただなんでこのような結果になるのか自分で書いて置きながらわからないので、自分なりに解説すると同時に疑問点を上げていきます。

まずchar* p = strより、strに入っている文字列abcdeをchar* p により、ポインタpの指すアドレスの番号ではなく、アドレスに入っている文字列abcde(文字コード)が渡される。そして、for文の++pにより文字列のアドレスに入っている文字コードの数値が+1されるのでポインタpが先頭のアドレスから表す文字列はbcdeとなる、それからpには文字コードが一つしか入らないようなので、「b」だけが入る、そして、**なぜかデバッグの結果より[0]にpに代入されたbが代入され、
strの中身の数列はbcdeとなっているので、なんで[6]にbが代入されないのかわからないですが**、*pに代入されたbが代入されたbが[0]として、bbcdeとなりました。

太い黒字で書いた部分の疑問がわかりません。
0. 疑問1 なぜpには文字コードが一つしか入らないのか。
0. 疑問2 なぜ[0]に
pに代入されたbが代入されたのか、個人的には文字列は最後に表示するためてっきりbcdebだと思っていました。
デバッグの画像です。

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

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

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

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

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

m.ts10806

2021/02/16 01:04

>太い黒字で書いた部分の疑問がわかりません。 自分の文章自分で理解できてますか?読むの赤の他人ってこと認識できてますか?
m.ts10806

2021/02/16 01:05

あ、いや。認識できてたらここまでこじれないか。
guest

回答4

0

やってる事の流れとしては

char str[] = { "abcde" };
はchar型のstr配列を宣言して"abcde"で初期化しています。

char p = str*
はポインタpを宣言してstr配列の一番最初の文字のポインタを代入しています。
&str[0]strは同じです。)

++p
はpのポインタに加算しています。(ループの最後に毎回実行される)

*++(p)
pのポインタの指す場所の数値(文字コード)に1加算しています。
「a」の文字コードに1加算すると「b」になります。

*printf("%s\n", &(p));
pポインタから文字列を表示。
(ちなみに**printf("%s\n", p);**←こう書いても同じです。)

以後、pのポインタの指す場所の数値が0(ヌル文字)になるまでfor内を繰り返す。

>>疑問1 なぜ*pには文字コードが一つしか入らないのか。

pはポインタだからポインタしかしか入りません。

pとだけ書くと今代入されてるポインタになります。
*pと書くと今代入されているポインタの指す場所の数値になります。

printf関数で書式に**%s**を指定した場合、引数に指定するのは文字列の配列のポインタです。
pを指定して文字が表示されるのは、文字列の配列のポインタが代入されているからです。

>>疑問2 なぜ[0]に*pに代入されたbが代入されたのか、

++pでポインタを加算しながら**++(*p)**でポインタが指してる場所の数値(文字コード)を加算してるので、str配列の全ての文字がズレて次の文字になってるだけです。

>>個人的には文字列は最後に表示するためてっきりbcdebだと思っていました。

恐らくポインタの仕組みが理解できていないか誤解をしているようです。
正直あなたがどういった誤解をしているのかわからないので、質問の意図も良く分かりません。

↓この辺のページでポインタを勉強をする事をお勧めします。
https://programming.pc-note.net/c/pointer.html
http://www.itsenka.com/contents/development/c/pointer.html
https://monozukuri-c.com/langc-pointer-interpretation/
https://www.cc.kyoto-su.ac.jp/~yamada/programming/pointer.html

投稿2021/02/15 22:01

kousatu

総合スコア225

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

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

carnage0216

2021/02/15 22:06

ありがとうございます。 >>なぜ*pには文字コードが一つしか入らないのか。 について、書いていただいた理由によりどんなプログラムにしても*pには >>*pと書くと今代入されているポインタの指す場所の数値になります。 よりそのポインタの表す場所のみの数値あるいは文字しか入らないため値あるいは文字が一つしか入らないということでしょうか?
kousatu

2021/02/15 22:22

ポインタ型で宣言した変数にポインタ以外を入るって考え方自体が間違ってます。 ポインタ型で宣言した変数はポインタしか入れてはいけません。 *pと表記すると代入されているポインタが指している場所に「アクセス」できるって考えた方がいいです。 *pでアクセスできるのは一か所だけって事です。 だから配列の次の数値にアクセスするには、p++と表記して指してるポインタを加算する必要があります。 とりあえず、リンク先に詳しく書いてあるんで読んでみて下さい。
guest

0

ポインタそのものをインクリメントしたりするとややこしさがますので、添字を使って書き換えてみましょう。

c

1#include <stdio.h> 2int main(void) { 3 char str[] = { "abcde" }; 4 for (size_t i = 0; str[i]; ++i) 5 { 6 ++str[i]; 7 printf("%s\n", &str[i]); 8 } 9}

さて、ここでstrは配列型ですが、配列型はいくつかの例外を除いて常に配列の先頭要素へのポインタとして読み替えられるのでした(array to pointer conversion)。つまり&str[i]str + iと等価です。なので

c

1#include <stdio.h> 2int main(void) { 3 char str[] = { "abcde" }; 4 for (size_t i = 0; str[i]; ++i) 5 { 6 ++str[i]; 7 printf("%s\n", str + i); 8 } 9}

のように書くこともできますね。

さて、このように書き換えると

疑問1 なぜ*pには文字コードが一つしか入らないのか。

はそもそも変数pを排除したのでなくなり

疑問2 なぜ[0]に*pに代入されたbが代入されたのか、

++str[i]のようになったので、配列の要素をインクリメントしていることがより明確にわかります。

このように添え字を使ってアクセスするとわかりやすくなると思います。

・・・と追うような話が前橋和弥氏の「C言語ポインタ完全制覇」にかかれていますので読んでみてください。ふるい方でも新版でも大丈夫です。

投稿2021/02/16 02:05

yumetodo

総合スコア5852

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

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

yumetodo

2021/02/16 11:11

他の回答者の方から十分に回答が付いてるので特に追加で回答する予定はありません。わからないことを質問する、それ自体もエネルギーが必要なことでその努力は素晴らしいと思います。また回答者たちはまあなんだかんだ言いながら具体的な質問に対しては回答をするでしょう。しかしもしC言語を理解したいというところに目標を置くならばあなたに今必要なのは質問をすることではなく、なにかまともな本かWebサイトをじっくり読むことだろうと思われます。たくさんの質問をする中で体系的に知識が体得できることは相当なレアケースであり、あくまでまずは良質な読み物をベースに行うべきだと思います。私や他の回答者のかたがすでに適当な読み物については紹介をしていますから、急がば回れ、まずは一度立ち止まってそれらを読みすすめる、そして理解したことを文章にまとめるという作業をする(ブログやQiitaなどで人に読まれるかもしれない環境を意識するとなおよし)、その上でわからないことが当然出てきますから質問をする、こうすることが大事なのではないでしょうか?
guest

0

まずchar* p = strより、strに入っている文字列abcdeをchar* p により、ポインタpの指すアドレスの番号ではなく、アドレスに入っている文字列abcde(文字コード)が渡される。

この段階で違っています。

C

1char* p

で用意されるのは、文字列の入った領域のアドレスを収納するポインタ一つです。

C

1char* p = str

では、文字配列 str の先頭アドレスが、文字列ポインタ p にコピーされます。
文字コードのコピーは行われません。

疑問2 なぜ[0]に*pに代入されたbが代入されたのか、個人的には文字列は最後に表示するためてっきりbcdebだと思っていました。

そして、for文の++pにより文字列のアドレスに入っている文字コードの数値が+1されるのでポインタpが先頭のアドレスから表す文字列はbcdeとなる、

for 文の今回 ++p となっている部分の実行は毎回のループの最後で行われるので、
第一回目のループでは、

C

1++(*p);

を実行した場合、一回目の段階ではポインタp の内容は最初のまま、
つまり、文字配列 str の領域の先頭アドレスなので、
ポインタp の指す領域の値は、"abcde" (str の値)の先頭一文字('a')がカウントアップされて 'b' となり、"bbcde" となります。

疑問1 なぜ*pには文字コードが一つしか入らないのか。

それから*pには文字コードが一つしか入らないようなので、「b」だけが入る、

C

1char *p

と宣言した場合、
p は 文字列領域のアドレスを持つポインタ
*p はそのポインタの指すchar型の変数という意味になります。
char 型は文字一つを示す型なので、文字コード一つしか入らないのは当たり前です。
この部分は完全に理解していないとポインタを使ったプログラムはできません。

投稿2021/02/15 22:18

kozuchi

総合スコア1193

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

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

carnage0216

2021/02/16 03:13

>>まずchar* p = strより、strに入っている文字列abcdeをchar* p により、ポインタpの指すアドレスの番号ではなく、アドレスに入っている文字列abcde(文字コード)が渡される。 なるほど、先頭のアドレスのみが入るのですね。 そして、*pによりアドレスのメモリの値を取るので、ポインタpのアドレスに入った先頭のアドレスの文字コードが入るのですね。 ちなみにcharは文字コードを受け取るための方ですか? またhttps://teratail.com/questions/322763に協力して頂けないでしょうか?
guest

0

等価なコードをポインタ使わずに書いてみました:

C

1#include <stdio.h> 2int main(void) { 3 4 char str[] = { "abcde" }; 5 6 for (int i = 0; str[i]; ++i ) 7 { 8 ++str[i]; 9 printf("%s\n", &str[i]); 10 } 11 12}

さて、これでも

1 なぜ str[0] には文字コードが一つしか入らないのか。
2 なぜ str[0] にbが代入されたのか、個人的には文字列は最後に表示するためてっきりbcdebだと思っていました。

って疑問を抱きますか?

投稿2021/02/16 02:04

編集2021/02/16 03:03
episteme

総合スコア16612

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

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

carnage0216

2021/02/16 02:18

エピスさんのことは嫌いだけど、感謝している部分があるのは事実です。複雑だな。
carnage0216

2021/02/16 02:19

あとできれば、デバッグの件も助けてほしいなあと。
episteme

2021/02/16 02:20 編集

ならば解決ってことでいいですか? 「デバッグの件」ってなんですか?
episteme

2021/02/16 02:29 編集

すでにいくつか回答ついています。なにを助けてほしいのですか? てか、僕の回答は不要ではありませんでしたか? 撤回しますか?
episteme

2021/02/16 02:35

ところで僕のこの回答、yumetodoさんのとまったく同じです。 yumetodoさんのにあなたの反応がないのが不可解。
carnage0216

2021/02/16 03:02

評価と反応しましたよ。
episteme

2021/02/16 03:04

僕の誤認です、失礼。 再度: 僕の回答は不要ではありませんでしたか? 撤回しますか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問