char *str = {0x61, 0x62, 0x0, 0x64};

ができないから、

char *str = "abcd";
str[2] = 0;

として、{0x61, 0x62, 0x0, 0x64} という文字列を作ってみた。

このポインタ str は解放する必要がない。
malloc( ) で確保したなら free( ) する必用がある。
普通のポインタは、もしかしたら 0x0 までしか
確保されていないのかなと思いました。

この場合では、str[3] == 0x64 だという結果になったけど、
それは str[2] の次のデータが 0x64 だったわけで、
str[2] に 0x0 が入った時点で、str[3] 以降の領域は
str とは無関係かもしれないと思いました。

つまり、char*型は、0x0 までの部分だけを確保し、
この例のソースでは、str[3] 以降の領域は確保されていないから
後で、知らないうちに値が変わっている可能性がある。

という想像をしてみたけど、あってますか?

このQ&Aに関連する最新のQ&A

A 回答 (7件)

こんにちは、honiyonです。



 ハズレです。
 最初に 4byte確保したなら、str[2] = NULL; としても 4byte確保されています。
 char*型はあくまで「char型へのポインタ」であり、メモリの操作は行いません。

 0x00 も立派な「データ」ですよ。

 char* = 文字列データ という意味合いが強いですが、あくまで char型は「0~255の整数型」であり、それ以外の用途にも使用される事があります。 char* でメモリを確保し、バイナリデータを扱う事だって出来ます。

 参考になれば幸いです(..
    • good
    • 0
この回答へのお礼

ありがとうございます。
ハズレでしたか。

メモリの操作は行わないという意味が分かりませんでした。

char *str = "abcd";
で5バイト確保される。
そして str を使う。
必要なくなったら、確保した5バイトを解放したい。
解放したい場合はどうしたらいいんですか?

char *str = "abcd";
printf("%x,%x,%x,%x,%x\n", str[0], str[1], str[2], str[3], str[4], str[5]);
str = "de";
printf("%x,%x,%x,%x,%x\n", str[0], str[1], str[2], str[3], str[4], str[5]);

結果は
61, 62, 63, 64, 0
64, 65, 0, 25, 23

この時、str が確保しているのはまだ5バイトですか?

char *str = "abcd";
の後に
str = "de";
としました。
どこかのサイトで、ポインタの値を書き替えてはいけない
と書いてあったのを見たような記憶があります。
この結果は企画にない結果だったんですか?

char *str;
で宣言したポインタに大きなサイズのデータを格納した場合、
プログラムが終了するまで、その大きなサイズを確保しているのは
よくないことだから解放したいと思って質問しました。

お礼日時:2002/03/21 19:35

> char *str[] = {0x61, 0x0, 0x64};


失礼しました。私のタイプミスです(笑)
ご指摘ありがとうございました。
*はいらないですね。
> char str[] = {0x61, 0x0, 0x64};

回答はみなさんの答えで的を得ています。
質問者がの処理系が違っていた場合には記述の曖昧さで悩んでしまうと可哀想かなと思ったので補足をしてみました。余計でしたら申し訳ないです。
そういう自分が上記のようなタイプミスしているくらいですから、私自身もまだまだ甘いですね。ただのタイプミスといえど挙動はかなり違いますからね。
    • good
    • 0

No.5 の方が「処理系依存」のことについて触れられていますが、それについてちょっとアドバイスを。



>signed か unsigned は処理系次第ではなかったでしたっけ。
>4バイトというのと、スタックに確保されるというのも、処理系次第ですよね。
 最適化するとレジスタを使ってしまったりする事も。

どちらも確かにその通りです。
でも A__ さんに理解して欲しいのは、
>char * 型は、文字列処理以外にも使用される、ということ
>ポインタ変数と文字列アドレスの関係について
という部分です。
(それを説明するには、どちらも十分な説明だったと思いますが。)

また、私はこの質問を、ポインタ変数を文字列で初期化した場合の、メモリとの関係について尋ねられているものだと思いました。
だとすれば、
> char *str[] = {0x61, 0x0, 0x64};
これでは文字列は生成されませんので、注意が必要です。
この記述では、それぞれのデータをアドレスとするポインタの配列ができるだけです。もちろん操作すると大変危険です。
    • good
    • 0

最近 C 言語をやっていないので懐かしいです。


char *str[] = {0x61, 0x0, 0x64};
なんていう宣言もありですね。

みなさんの回答でちょっと気になった点を。

(あくまで char型は「0~255の整数型」)
signed か unsigned は処理系次第ではなかったでしたっけ。

(関数内で宣言された char * 型の str は、スタックメモリ上に確保されます。無論、確保されるサイズは4バイトです。)
4バイトというのと、スタックに確保されるというのも、処理系次第ですよね。
最適化するとレジスタを使ってしまったりする事も。

なんんだかややこしい話ですね・・・
    • good
    • 0

おもしろい発想です。


C言語勉強し始めの頃は、こんな疑問に大いにぶつかってください。
今回は、皆様の言うとおり、はずれですが。

おまけ情報です。
char*はCスタイルの文字列と呼ばれますが、これは\0(0x00)までを文字範囲とする、という規定の基に、様々な操作がなされます。
確保した領域の中に\0が見つからなければ、文字列操作関数は、確保してある領域を超え、一般保護違反というエラーが発生する危険性を秘めます。

VBやJAVA、Perlの文字列は、\0で終わるという保証はなく、わざわざこの文字列は何文字あるという情報と一緒に、変数を管理します。
でも、これによって\0を途中に含む文字列が作れますし、確保した範囲を超えてアクセスする危険性も低くなります。

ポインタマニアの、はぽるんでした。
    • good
    • 0
この回答へのお礼

ありがとうございます。

お礼日時:2002/07/14 09:17

# 何か、メモリとポインタ変数との間に、変な誤解を持たれているようですが・・・



「文字列」というのは、確保されるものではありません。例えば、
  char *str = "abcd";
とすると、コンパイルした時点で、プログラム内部のどこかに 0x61, 0x62, 0x63, 0x64, 0x00(全部で5バイト)が用意されます。(文字列の最後には、'\0'が付加されることをお忘れなく!)
この「用意」というのは、「プログラム実行時にメモリを確保してデータが配置される」のではなく、「コンパイルされたプログラムに、その一部として既に存在している」ということです。
ソース名が hoge.c だとすれば、hoge.exe の中には、"abcd" が含まれているのです。

(つまり)文字列はプログラムの一部なので、プログラムがメモリ上にロードされた時点でアドレスが決定されます。"文字列" は、そのアドレスを持っています。

関数内で宣言された char * 型の str は、スタックメモリ上に確保されます。無論、確保されるサイズは4バイトです。
str = "abcd" となっているので、str の確保されている4バイトの領域に、"abcd" が存在するメモリのアドレスが代入されます。
プログラム実行時に行われるのは、たったこれだけです。
つまり、ポインタ変数 str と、"abcd" が存在するメモリの間には、そのアドレスを知っていること以外、何の関係もないのです。

alloc系関数を用いた動的メモリ確保の場合も同じです。
malloc は必要サイズのメモリを確保し、その先頭アドレスを返します。
→これをポインタ変数で受け取るのは、メモリにアクセスするのに必要だからであって、このポインタにメモリを割り当てるわけではありません。
次にこのメモリ領域を解放する場合、malloc が返したアドレスを使って、free が解放処理を行います。
→無論アドレスを受け取ったポインタ変数を解放するわけではありません。ポインタ変数を介して、確保したメモリのアドレスを free に知らせるだけです。
(ですので「ポインタを解放する」という表現は、明らかに正しくありません。)

話を質問に戻しますが、文字列 "abcd" が存在していた5バイトの領域が、勝手に使用されてしまうことはありません。
意図的に str[2] = 0 ('\0'であるべき) としても、その5バイトの領域の内容が 0x61, 0x62, 0x00, 0x63, 0x00 になるだけであって、解放とかそういう次元の話は、全く関係ありません。
表示した時に「ab」しか表示されないだけであって、
  str[2] = 'Z';
とすれば、「abZd」が、いつでも必ず表示されます。
    • good
    • 0

> このポインタ str は解放する必要がない。


むしろ、解放したらまずいです。

たぶん。判断されたのは
printfで表示しても
abしか出なかったからだと思いますが、これは\0(0x00)がCに置ける文字列の終わりを示すコードになっているからです。

もし、確保されていなければ、str[3]のアクセス時に不正終了しかねません。「確保されていないメモリ」にアクセスするわけですから。
    • good
    • 0

このQ&Aに関連する人気のQ&A

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

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QC言語のソースコードの書き方

C言語のソースコードの書き方に関する質問です。
0を5個と1を4個の、合わせて9個の数字を並べて出来上がる数列のパターン(126通り)を全て羅列させるプログラムを作りたいと考えていますが、そのためにどういった方針を立ててソースコードを書けばよいかが分かりません。
どういった構造かだけでも構いませんので、教えて頂けると幸いです。
よろしくお願いします。

Aベストアンサー

という方針で書くとこんな感じね。
#include <stdio.h>

void
print_pattern(char pattern[], int size)
{
for (int i = 0; i < size; i++) {
printf("%c", pattern[i]);
}
printf("\n");
}

void
iter(char pattern[], int end, int n, int m)
{
if (n == 0 && m == 0) {
print_pattern(pattern, end);
return;
}

if (n == 0) {
pattern[end] = 'b';
iter(pattern, end + 1, n, m - 1);
return;
}
if (m == 0) {
pattern[end] = 'a';
iter(pattern, end + 1, n - 1, m);
return;
}

pattern[end] = 'b';
iter(pattern, end + 1, n, m - 1);
pattern[end] = 'a';
iter(pattern, end + 1, n - 1, m);
}

int
main(void)
{
int m = 5, n = 4;
char pattern[m + n];
iter(pattern, 0, m, n);
return 0;
}

という方針で書くとこんな感じね。
#include <stdio.h>

void
print_pattern(char pattern[], int size)
{
for (int i = 0; i < size; i++) {
printf("%c", pattern[i]);
}
printf("\n");
}

void
iter(char pattern[], int end, int n, int m)
{
if (n == 0 && m == 0) {
print_pattern(pattern, end);
return;
}

if (n == 0) {
pattern[end] = 'b';
iter(pattern, end + 1,...続きを読む

Qchar *name1[4] とchar name2[][4] の違いについて

C言語のことで質問があります。

char *name1[4]は
char *name1[4] = {"abcdefghi","jkl","l","mn"};
と宣言でき,ポインタを4つ確保した形となりました。

char name2[][4]は
char name2[][4] = {"abc","def","ghi","jkl","mno","pqr","stu","vwx"};
と4文字以内の文字列を初期化した数だけ確保した形となりました。

この結果からchar *name1[4]の意味は,char name2[][4]ではなくchar name2[4][]に近いと思いました。
しかし,char name2[4][]ではポインタを4つ確保した事にはならないみたいでコンパイルが通りません。
*name1[4]では4つのポインタを確保できるのに~と思ってしまいます。

ポインタと配列は別物と考えるべきなのでしょうか?
訳の分からない質問かもしれませんが,
何卒ご指導いただくようよろしくお願いします。

Aベストアンサー

ポインタと配列の違いというのは、変数と定数の違いのようなものです。

話を簡単にするために、一次元配列から考えましょう。

char *p1; と定義した時のp1は、いうまでもなくポインタで、
これは変数です。p1は任意の文字列を指すことができます。
char a1[4]; と配列の形で定義した場合のa1については、
a1[0]やa1[1]等を、通常のchar型の変数と全く同じように扱うことが
できます。しかし、a1自体は、例えば a1 = p1; のように値を代入する
ことができません。(逆の p1 = a1; は可能。)つまり、この場合のa1は、
変数ではなく、定数のようなものなのです。

複合的なケースについて見てみましょう。
char **q1; ポインタへのポインタ
 q1,*q1,**q1,q1[0],*q1[0],q1[0][0] のいずれも変数として
 扱うことができます。(値を代入することが文法的に許されます。
 ただし、実行時にはアクセス違反になる場合もあります。)
char q2[4][4]; 二次元配列
 q2,q2[0]は変数として扱うことができません。q2[0][0]のように
 して、初めて変数として扱えるようになります。
char *q3[4]; ポインタの配列
 q3は変数として扱うことができませんが、q3[0],*q3[0],q3[0][0]
 はいずれも変数として扱うことができます。
 なお、この定義は char *(q3[4]); とした場合と全く同じ意味です。
char (*q4)[4]; 配列へのポインタ
 q4,(*q4)[0],q4[0][0]はいずれも変数として扱うことができます。
 しかし、*q4,q4[0]は変数として扱うことができません。

char *name1[4]; と char name2[4][]; は確かに似ています。しかし
違うところもあります。それは、name1[0] が変数として扱えるのに
対し、name2[0] には値を代入できないという点です。(データの
具体的な構造については、inthefloiさんが書いておられる通りです。
> char name2[4][]ではポインタを4つ確保した事にはならないみたい
というのも、全くその通りで、配列の定義では、ポインタ変数の領域
を確保する余地はないのです。

ポインタと配列の違いというのは、変数と定数の違いのようなものです。

話を簡単にするために、一次元配列から考えましょう。

char *p1; と定義した時のp1は、いうまでもなくポインタで、
これは変数です。p1は任意の文字列を指すことができます。
char a1[4]; と配列の形で定義した場合のa1については、
a1[0]やa1[1]等を、通常のchar型の変数と全く同じように扱うことが
できます。しかし、a1自体は、例えば a1 = p1; のように値を代入する
ことができません。(逆の p1 = a1; は可能。)つまり...続きを読む

QC言語のソースコードについて教えてください。

以下のソースコードを学習用C言語開発環境で行ったのですが、
『ファイル「C:/Users/ユーザー名/AppData/Local/EasyIDEC/project/タイトル/main.c」の
「41行目」で記述エラーを発見しました。
「,」を付け忘れています。』

という、コンパイルエラーが表示されました。
何度も見直したのですが、よくわかりません。

#include <stdio.h>

int main(int argc, char *argv[])
{
char answer ;
answer = 'n' ;

while(answer =='n')
{
int input ;
input = 0 ;
int add ;
add = 1 ;
int sum ;
sum = 0 ;

printf("数値を入力して下さい。:") ;
scanf("%d", &input ) ;

int i ;
i = 0 ;

while(i < input)
{
sum =sum + add ;
printf("\n%d",sum) ;
i++ ;
add++ ;
}

printf("\n1から%dまでの総和は、%dです。" , input , sum) ;

while(1)
{

printf("\n終了しますか? y/n:") ;
scanf(" %c , &answer) ;

if( (answer != 'y') && (answer != 'n') )
{
printf( "y or nを入れてください。") ;
}
else
{
break ;
}
}
}
return 0 ;
}

以下のソースコードを学習用C言語開発環境で行ったのですが、
『ファイル「C:/Users/ユーザー名/AppData/Local/EasyIDEC/project/タイトル/main.c」の
「41行目」で記述エラーを発見しました。
「,」を付け忘れています。』

という、コンパイルエラーが表示されました。
何度も見直したのですが、よくわかりません。

#include <stdio.h>

int main(int argc, char *argv[])
{
char answer ;
answer = 'n' ;

while(answer =='n')
{
int input ;
input = 0 ;
int add ;
add = 1 ;
int sum ;
sum = 0 ;

printf("...続きを読む

Aベストアンサー

>>おかげで、エラー表記されずに、プログラムが実行されました。

これはコンパイルがうまく完了したってことでしょうか?できあがったプログラムが実行できたってことではないですよね?そうなら

>>’タイトル’は内部コマンドまたは外部コマンド、操作可能なプログラムまたはバッチ ファイルとして認識されていません。」

なんて問題は起きないはすですからね。

できあがったファイルは、XXXX.EXEのように拡張子のEXEがついていますか?もしXXXX.OBJであれば、リンクができていませんから、実行できません。

学習用C言語開発環境の使い方を確認してみてください。

P.S.
昔は、コンパイラを使うのは大変でしたが、今は楽ですね。CではなくPascal系コンパイラーですが、カセットテープに入っていて、コンパイラの読込にテープレコーダで15分かかったりとか、まあ大変だけど面白い時代でした。

Q副プログラム内(void mystery(char s1[],char s2[]))の動作確認文 

お忙しい中失礼します。
下記のプログラム内の動作について質問があります。宜しければご回答願います。

void mystery(char s1[],char s2[])
{
int i=0;
while(s2[i]!='\0'){ //s2[i]内に文字が入力され、エンターキーが入力されるまで{s1[i] = s2[i]; ++i;}内の動作を行う。
s1[i] = s2[i];    //s1[i] を基準にs2[i]の文字数を++iを使い、カウントする。
++i;         //++iはただs1[i] とs2[i]の文字が合致してるか確認を行う。s1[]=”Good”なら s2[]=”Good”の各文字が合致してるかどうか。
}

s1[i] = '\0';    //s1[i]にエンターキーが入力されて、void mystery(char s1[],char s2[])内のループを抜ける。
return;       //s1[i] = '\0'で'\0'が定義されているのでreturn 0;でない?
}

↑上記動作質問://より右側の文章は文章的に正しいでしょうか?
void mystery(char s1[],char s2[])内でどんな動作をしてるのかが、イマイチよく分からないのです。




↓下記のプログラム
#include <stdio.h>
#include <stdlib.h>
void mystery(char [], char[]);

int main()
{
char m1[81],m2[81];
int i;
printf("Message?");
gets(m1);
mystery(m2,m1);
puts(m2);

system("PAUSE");
return 0;
}

void mystery(char s1[],char s2[])
{
int i=0;
while(s2[i]!='\0'){
s1[i] = s2[i];
++i;
}

s1[i] = '\0';
return;
}

お忙しい中失礼します。
下記のプログラム内の動作について質問があります。宜しければご回答願います。

void mystery(char s1[],char s2[])
{
int i=0;
while(s2[i]!='\0'){ //s2[i]内に文字が入力され、エンターキーが入力されるまで{s1[i] = s2[i]; ++i;}内の動作を行う。
s1[i] = s2[i];    //s1[i] を基準にs2[i]の文字数を++iを使い、カウントする。
++i;         //++iはただs1[i] とs2[i]の文字が合致してるか確認を行う。s1[]=”Good”なら s2[]=”Good”の...続きを読む

Aベストアンサー

うーん。。。
動作の説明としては全て間違いです。

>while(s2[i]!='\0'){
s2のi番目の要素が終端文字で無い間繰り返し処理します。
#エンターキー云々は関係ありません。

>s1[i] = s2[i];
s1のi番目の要素にs2のi番目の要素をコピーしています。
#比較ではなく代入です。

>++i;
ここでのiは文字列の要素を表す要素番号に過ぎません。
#次の文字へ進むだけで、カウントなどしていません。

>s1[i] = '\0';
s2が文字列の終わりを検出したので、
ループを抜けてs1にも文字の終端を書き込んでいます。
#ここでは既にループを抜けた後です。

>return; 
関数の戻り値はvoidつまり「無し」なので
returnで評価される式も在りません。
#疑問系でコメントを書くなら書かない方が良いです。
#混乱のもとですから。。。

短くすると・・・:-p
void mystery(char *s1, const char *s2){
  while (*s1++ = *s2++);
}

うーん。。。
動作の説明としては全て間違いです。

>while(s2[i]!='\0'){
s2のi番目の要素が終端文字で無い間繰り返し処理します。
#エンターキー云々は関係ありません。

>s1[i] = s2[i];
s1のi番目の要素にs2のi番目の要素をコピーしています。
#比較ではなく代入です。

>++i;
ここでのiは文字列の要素を表す要素番号に過ぎません。
#次の文字へ進むだけで、カウントなどしていません。

>s1[i] = '\0';
s2が文字列の終わりを検出したので、
ループを抜けてs1にも文字の終端を書き込んでいま...続きを読む

QC言語ソースコードに関する質問です。

以下の数列について,初項から第15項までを求めるプログラムと実行結果を示せ。
0 1 1 2 3 5 8 13 21(ただし,初項=0,第1項=1とする。)

ソースコードを書くと、エラーがでた。
#include <stdio.h>
int fib(int n)
{
if(n==1 || n==2)
return 1;
else
return fib(n-1)+fib(n-2);
}
int main(void)
{
int n;
for(n=0;n<17;n++)
printf("%d,",fib(n));
}

正しソースコードを教えてください!

よろしくお願いします。

Aベストアンサー

#include <stdio.h>

void fib(int i, int j, int n)
{
if (n == 1)
{
printf("%d\n", i);
}
else
{
printf("%d\n", i);
return fib(j, i + j, n - 1);
}
}

int main(void)
{
fib(0, 1, 15);

return 0;
}

Qdc.TextOut(0 ,0 , *str) ;について

環境 WIN98 VC++6.0 MFC にて

パターンBはOKですが、パターンAだと不正な処理で落ちてしまいます。

どうしてなのかお教えください。

void CFffView::OnPaint()
{
CPaintDC dc(this);
//パターンA
CString* str ;
str = (CString*)("999");
dc.TextOut(0 ,0 , *str) ;

//パターンB
CString aaa ;
aaa = (CString)("999");
dc.TextOut(0 ,0 , aaa) ;
}

Aベストアンサー

両方ダメ。
Aのパターンで動くのは、たまたま。

CString aaa ;
aaa = "999";
dc.TextOut(0 ,0 , aaa) ;

これで十分。

あえてキャストするんだったら、
CString aaa ;
aaa = (LPCSTR)"999";
dc.TextOut(0 ,0 , aaa) ;


aaa=のところでは、ただの代入が行われているわけではありません。
オーバーロードされたオペレータが呼ばれています。


>str = (CString*)m_array.GetAt(i) ;

これは、m_arrayの要素にCString*を入れていて、初めて成り立つ式です。
値をいれているところと、m_arrayの宣言を確認してください。

str = (CString*)("999");
も、
aaa = (CString)("999");
も、リテラル文字列をつっこもうとしています。
リテラル文字列とCStringはまったく別物です。

Qc言語のソースコードを教えて下さい

キーボードから10個の正整数値を読み込み,合計値を表示するプログラムを作りなさい。
ただし,キーボードから読み込んだ値はint型変数xにしまわれるものとし,変数はこのxと回数を数えるint型変数countと合計値をしまうint型変数sumのみを用いることとする。

このプログラムのソースコードを教えて下さい。
解説もよろしくお願いします。

Aベストアンサー

一例です。
添付のURLを参照して下さい。
因みに、平均値も算出しているが気にせずに、後はご自身で変数、コードを要調整して下さい。

参考URL:http://www.geocities.jp/kenji_y0328/crenshu/renshu/r021.gif

Qchar gyou[1024];でcharの表現範囲は-128~127間でと!gyou[1024]の

#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
char gyou[1024];
int gyousuu = 0;
if ( argc < 2 ){
printf("file mei ga nai\n");
return -1;
}
fp = fopen(argv[1], "r");
if ( fp == NULL ){
printf("fopen dekinai\n");
return -2;
}
while(fgets(gyou, sizeof(gyou), fp) != NULL){
gyousuu++;
}
fclose(fp);
printf("gyousuu=%d\n", gyousuu);
return 0;
}
 以上のプログラムは行数を計算してくれるプログラムです。
  計算結果が
  gyousuu=22 とでます。
 さて、char gyou[1024];でcharの表現範囲は-128~127間ですが、
 gyou[1024]の[1024]とは関係はありますでしょうか!?
  [1024]の意味は”要素数”と参考書に鉛筆書きがありました。
 charの表現範囲である1024は、はるかに超えているみたいですが?
  dharの表現範囲を1024が超えたとしても特に問題はなさそうです!
  このプログラムは動いていますのでは正常です。
  私の
  考え方としまして、何か誤りがありますでしょうか?
  よろしくお願いいたします。

#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
char gyou[1024];
int gyousuu = 0;
if ( argc < 2 ){
printf("file mei ga nai\n");
return -1;
}
fp = fopen(argv[1], "r");
if ( fp == NULL ){
printf("fopen dekinai\n");
return -2;
}
while(fgets(gyou, sizeof(gyou), fp) != NULL){
gyousuu++;
}
fclose(fp);
printf("gyousuu=%d\n", gyousuu);
return 0;
}
 以上のプログラムは行数を計算してくれるプログラムです。
  計算結果が
...続きを読む

Aベストアンサー

> さて、char gyou[1024];でcharの表現範囲は-128~127間ですが、
> gyou[1024]の[1024]とは関係はありますでしょうか!?
ない。
1024 のほうはただ単に領域の個数を表しているだけで、読み込もうとするファイルの 1 行のバイト数がこれを超えない限り別に 1000 でも 3327 でも構わない(ある程度以上大きくなると別の問題が出てくるが)。
ただ単に 1024 = 2^10 でプログラマにはよく見る数字、かつ、普通のテキストなら 1 行が収まりそうな長さなだけ。

Qソースコードの間違い (C言語)

変数に、文字列を入れた配列の文字列の最後の要素数を入れたいのですが(つまり'\0')、うまくいきません。いつも2個多い値になってしまいます。

#include <stdio.h>

void main() {
char moji[100]={0};
int c=0;

fgets(moji,sizeof moji,stdin);

while( moji[c] != '\0' ) ++c;

printf("\n%d\n",c); //
}

例えば5文字の1ビット文字を入れると、最後の文字はmoji[4]にあるのでprintfで4と表示されるはずじゃないですか。でも6になるんです。いつも+2の値になるんですよ。どうやらfgetsを使っているからそうなるらしく、scanfを使うと結果は1多い値に、普通に配列に直接文字列を代入すると正常な結果になります。別にcに-2してもいいのですが、それはなんだか癪といいますか・・・。なぜこういうことがおきるのでしょうか?回答よろしくお願いします。

Aベストアンサー

>なぜこういうことがおきるのでしょうか
そのmoji[]の余計な部分にはどんなコードが入っているかは確認していますか?
リターンキーも「キー入力」の一つですよ。

Qchar *str; と char* str;

char *str; と char* str;
どっちも同じことを意味しているんですか?

Aベストアンサー

同じことを指している、というのは、先の回答の通りです。

また、ひとつの宣言で変数を複数宣言したときに、char* str という表記は間違い
易いじゃないか、ということが言われているのも事実です。実際、いろいろな C のソースを
見ていても、まずアスタリスクを型につけて書くのは、まずお目にかかれません。

ただ C++ では、char* str という宣言も良く使われています。

C++ に限らずオブジェクト指向の言語は、強く型を意識するので、「文字のポインタ型」と
いう意味で、まとめて書く方が馴染むのでしょう。ちなみにそういう風な人たちは

char *str1, *str2;

とは、書けない体になっています。

char* str1;
char* str2;


変数の宣言だと、C に慣れていれば、char* str というのはちょっと違和感があるのは
私も分かりますが、関数のプロトタイプ宣言だと、どちらの方がすっきりしますか?

extern char *memcpy(char *, const char *);

extern char* memcpy(char*, const char*);


# まあ、どっちが正しい、っていうんじゃ無いんですよね

同じことを指している、というのは、先の回答の通りです。

また、ひとつの宣言で変数を複数宣言したときに、char* str という表記は間違い
易いじゃないか、ということが言われているのも事実です。実際、いろいろな C のソースを
見ていても、まずアスタリスクを型につけて書くのは、まずお目にかかれません。

ただ C++ では、char* str という宣言も良く使われています。

C++ に限らずオブジェクト指向の言語は、強く型を意識するので、「文字のポインタ型」と
いう意味で、まとめて書く方が馴染む...続きを読む


人気Q&Aランキング

おすすめ情報