プロが教える店舗&オフィスのセキュリティ対策術

C言語初心者です。
宜しくお願い致します。

char ss[10];

ss[0] = 'A';
ss[1] = 'B';
ss[2] = 'C';
ss[3] = 0; /* '0' ではなく、0 */
ss[4] = 'E';
ss[5] = '0';
ss[6] = 'G';
ss[7] = '\0';

printf("%s",ss);

上記の場合、出力されるのは、ABC までだと思いますが、
数値0 の所で、出力を終了させずに、Gの所まで出力させることは
できますでしょうか。
(「そもそも、なぜそんなことをしたい?」という疑問は、とりあえず横に置いておいて下さい。)

なお、文字'0'の所では出力は終了しない、ということは理解しております。
つまり、数値0ではなく、文字'0'の場合には、そのまま「0」が出力される、と理解しております。

数値0 と NULL文字¥0 の所で出力は終了する、という理解のもと、
質問をさせて頂いております。

宜しくお願い致します。

A 回答 (8件)

数値0をそのまま0として出力したいなら、printfを使えばいいだけです。


つまり、ss[i]に数値が入っているのなら、
printf("%d",ss[i]);
です。
一方、ss[i]に入っている値を文字として出力したいのなら、putcharを使います。
putchar(ss[i]);

ということは何らかの条件でこの2つを切り替える必要があります。どんな条件で切り替えましょうか。
    • good
    • 0
この回答へのお礼

>ss[i]に数値が入っているのなら、printf("%d",ss[i]);

文字'0'として出力しても、数値0として出力しても、
見た目に違いはないとは思いますが、
出力方法には様々なカタチがあることを勉強させて頂きました。

こちらの回答を受け、さらにモヤモヤが広がりました…。

printf("%d",ss[3]);  /* ss[3] = 0; ★ 0 が出力される。*/

printf("%s",ss[5]);  /* ss[5] = '0'; ★ 0 が出力される*/

printf("%s",ss[3]);  /* ss[3] = 0; ★ 何も表示されない?!*/

文字列として 0 を見た場合には、それは終端文字として解釈されるため、
何も表示せずに終了となるのかな、と私は考えたわけです。
(実際にやってみれば分かることではありますが、
結果的にそうなったからと言って、それがそのまま、考え方の上でも正しかったとは
言い切れないので、こうして質問をさせて頂いております。)

何かおかしな所がありましたら、ご指摘下さい。

お礼日時:2010/11/11 12:22

> 数値0 の所で、出力を終了させずに、Gの所まで出力させることは


> できますでしょうか。

すでにやり方までご助言いただいているはずですが。

#include <stdio.h>

int main( void )
{
char ss[] = { 'A', 'B', 'C', 0, 'E', 0, 'G', 0 };

fwrite( ss, sizeof(char), sizeof(ss), stdout );
fwrite( "\n", sizeof(char), sizeof("\n"), stdout );
}

文字列として処理すれば、文字列の定義が'\0'までの連続した文字群ですからできません。
※ printfの"%s"変換など
が、文字列として処理しなければ(改行まで処理するだとか、文字数を指定して処理するだとかすれば)問題なくできます。

例えばUTF16ではASCIIの印字可能文字に'\0'が含まれますので、UTF16使う端末では実際出力されます。
※ UTF16文字列処理に専用の関数作ったり大きさを指定するなどで別の方法で行ったり。fgetsの様な'\n'('\0'以外の文字)を終端に使う関数なども使えます。

http://homepage1.nifty.com/nomenclator/unicode/u …

※ 上記ページに『UCS-2のU+0041の文字(すなわち 'A')を,UTF-16BEでは00 41という2バイトで, UTF-16LEでは41 00という2バイトで表します』と解説されている通り。
    • good
    • 0
この回答へのお礼

より突っ込んだ回答を提示して頂き、ありがとうございます。
ぼんやりとではありますが、さらによく分かるようになった気がします。
参考にさせて頂きます。

お礼日時:2010/11/12 16:04

ちょっと抜けがあったので、追加。



>printf("%s",ss[3]);  /* ss[3] = 0; ★ 何も表示されない?!*/
は、環境によっては落ちずに"(null)"など表示される場合があります。
# GNU libc ライブラリあたりでそんな動作したことがあったと…
    • good
    • 0
この回答へのお礼

こちらも参考になりました、ありがとうございます。

お礼日時:2010/11/11 17:09

>printf("%s",ss[5]);  /* ss[5] = '0'; ★ 0 が出力される*/


>printf("%s",ss[3]);  /* ss[3] = 0; ★ 何も表示されない?!*/

こちらは、期待する動作はしないでしょう。
一般保護違反などで落ちると思われます。

書式%sが要求するのは、const char *(またはchar *)です。
渡したものはchar配列中の1要素なのでcharです。
printf()はcharで渡された'0'を「文字列が格納されている先頭アドレス」として解釈し、参照しようとしますので…
結果として一般保護違反(アクセス違反)となります。

printf("%c",ss[5]);  /* ss[5] = '0'; ★ 0 が出力される*/
printf("%s",&ss[3]);  /* ss[3] = 0; ★ 何も表示されない?!*/
ならば問題ありませんが…

>printf("%d",ss[3]);  /* ss[3] = 0; ★ 0 が出力される。*/

こちらは想定している通りです。
# "%d"の方は、printf()内部で数値=>数字変換し、その結果を出力しています。
    • good
    • 0
この回答へのお礼

>一般保護違反などで落ちる
>printf()はcharで渡された'0'を「文字列が格納されている先頭アドレス」として解釈

初心者である私には、このあたりはまだ難しかったです。
たぶん、もう少しC言語の学習が進めば、理解できることなんだろうと思います。
その時まで、温存しておきます。笑
きっと、「型(あるいは、書式)の問題」なんでしょうね。

お礼日時:2010/11/11 17:09

JIS C の規格に従っている限り, いかなる処理系においても「整数リテラル 0」と「文字リテラル '\0'」は等しくなります (int の 0 として扱われる).


つまり, ほかの回答でも言われているのですが「同じく 0 であるのに ss[3] では止まらず ss[7] で終了する」ためには, ss 以外の「何か」を必要とします.
    • good
    • 0
この回答へのお礼

>「整数リテラル 0」と「文字リテラル '\0'」は等しくなります (int の 0 として扱われる).

ありがとうございます、とてもよく分かりました。

お礼日時:2010/11/11 12:06

まず、一般的な処理系では「数値0 と NULL文字¥0」は等しく0であることは


ご存知でしょうか?
つまり、ss[3]とss[7]の区別がつかないことを意味します。
ss[7]で文字列が終了することは、別の方法で明らかにする必要が発生します。

それを踏まえて関数をつくると以下のような感じでしょうか。

#include <stdio.h>

void myprint(char *src, int len)
{
int i;
for(i=0; i<len; i++)
{
if( (src[i] >= 'A' && src[i] <= 'Z') ||
(src[i] >= 'a' && src[i] <= 'z') ||
(src[i] >= '0' && src[i] <= '9') )
putchar(src[i]);
}
}

int main(int argc, const char *argv[])
{
char ss[10];

ss[0] = 'A';
ss[1] = 'B';
ss[2] = 'C';
ss[3] = 0; /* '0' ではなく、0 */
ss[4] = 'E';
ss[5] = '0';
ss[6] = 'G';
ss[7] = '\0';

myprint(ss, 10);

return 0;
}



数値0は表示しないように作ってありますが、もし数値0を文字列0として
表示したいのでしたら、if()文追加して拾ってあげればいいと思います。

ちなみにC99環境でしたら、isgraph()等で判定するとエレガントです。
    • good
    • 0
この回答へのお礼

>まず、一般的な処理系では「数値0 と NULL文字¥0」は等しく0であることは
ご存知でしょうか?

はい、参考書には、そのような記述がありましたが、
その記述に対し、私は自分の読解に自信が持てず、半信半疑でおりました。
(しかし、今、おかげさまで、確実な理解へと変わりました。)

>それを踏まえて関数をつくると以下のような感じでしょうか。

わざわざ、私のためにありがとうございます。
私にはまだ難しいコード例でしたので、
もう少し力を付けてから改めて解読してみたいと思います。

お礼日時:2010/11/11 12:04

どんな出力結果を望むのかによります。


また、

ss[0] = 'A';
ss[1] = 'B';
ss[2] = 'C';
ss[3] = 0; /* '0' ではなく、0 */
ss[4] = 'E';
ss[5] = 0;
ss[6] = 'G';
ss[7] = '\0';

とか、

ss[0] = 'A';
ss[1] = 'B';
ss[2] = 'C';
ss[3] = 0; /* '0' ではなく、0 */
ss[4] = 'E';
ss[5] = 0;
ss[6] = 'G';
ss[7] = 0;
ss[8] = 'I';
ss[9] = '\0';
などの場合にはどうなってほしいのでしょうか?
    • good
    • 0
この回答へのお礼

数値0を、そのまま 0 として出力させられるのか、について考えてみたかったんです。

つまり、「~がしたい」という質問ではなく、
「~はできるのか?」といった主旨の質問になります。
分かりにくくて、すみません。

単純に 0 という文字を出力したいのであれば、
'0'として考えれば、希望は叶いますよね。

ということで、
私が知りたいことは以下のようなことになります。

'0'ではなく、0 として配列に格納したデータを、
0 として出力することは可能なのか、
もし、可能な場合、その方法はどうなるのか、ということです。

と、ここまで書いてみて、
不毛な質問をしている気がしてきました…。
回答を頂いておきながら、こんなことを言って、すみません。
もし何かアドバイスを頂けましたら、とても嬉しく思います。
宜しくお願い致します。

お礼日時:2010/11/11 11:08

ss[3]をどう出力させたいですか。


例えば
int i;
for(i=0;i<7;i++) {
 putchar(ss[i]);
}
でできると思いますが、ss[3]はコントロール・コードになるのでどう表示されるかはコンソール依存でしょう。
    • good
    • 0
この回答へのお礼

>ss[3]をどう出力させたいですか。

ABC0E0G と出力させたいと考えております。
それであれば、
"ABC0E0G" として出力させればいいじゃないか、と言われてしまいそうですが。笑

数値0を「0」として、つまり、文字として、出力したい場合には、
素直に'0'として考えて出力すればいい、ということなのでしょう。

だから、配列の1要素として、数値0 を入れる場合には、
それは終端文字として解釈される、と考えるべきなのでしょうね。

>ss[3]はコントロール・コードになるのでどう表示されるかはコンソール依存でしょう

なるほど、参考にさせて頂きます。

お礼日時:2010/11/11 10:59

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!