• ベストアンサー

ポインタでの文字列操作

C-CGIを今作っていて、猫で分かるプログラミングを見ながら勉強しています。 そこで、http://www.kumei.ne.jp/c_lang/intro/no_82.htm のプログラムの変数 char name[64], address[256], sex[16], onwa[16], inken[16], seikaku[128]; をすべてポインタ型の文字列に置き換えたらエラーが起こってしまいました。 char *name, *address, *sex, *onwa, *inken, *seikaku; こんな感じに。エラーと言いましても、コンパイラが吐き出すエラーではなく、実行すると強制終了をOSから喰らいます。何故でしょうか? 原因と解決方法をどうかご指南ください。

質問者が選んだベストアンサー

  • ベストアンサー
  • gimmick
  • ベストアンサー率49% (134/270)
回答No.2

>実行すると強制終了をOSから喰らいます。何故でしょうか? 初期化していないポインタを使ってメモリにアクセスしているからです。例えば不定な値が入っているポインタnameを使って*nameを書き換えようとすると、一般的にメモリアクセス違反になります。適当なバッファを用意して、バッファへのポインタをname等に代入してやる必要があります。 #もっとも、一番簡単な解決方法は元の配列を使った方法に戻す事でしょうね。あえて配列を使う理由があるのでしょうか?

その他の回答 (2)

  • gimmick
  • ベストアンサー率49% (134/270)
回答No.3

#2です。 最後の「あえて配列を使う理由があるのでしょうか?」は「あえてポインタを使う理由があるのでしょうか?」の間違いです。

  • PAPA0427
  • ベストアンサー率22% (559/2488)
回答No.1

宣言すればよいと言うものではありませんよ。 ポインタ型で宣言したら、実体の変数化、構造体で初期化しなければつかえません。 コーディングをそのまま変更しただけなら、初期化作業はされていませんので、ポインタの値が不定になっていますので、実行するとメモリ上のどこに設定していいかわからない、設定不能になるため、エラーで落ちます。

関連するQ&A

  • charポインタへの文字列による動的確保

    char *c=new char("abcd"); のようにして、cに"abcd"のポインタを代入しようとしたのですが、 error C2440: '初期化中' : 'const char [5]' から 'char' に変換できません。 と出てきてうまくいきません。 どの様にすれば、メモリ確保と同字に文字列で初期化できるのでしょうか?

  • ポインタの基礎について

    Cのポインタに関して、質問されて答えられなかったものがありまして、お尋ねしたいと思います。 long型の変数へのポインタは[ ]型 char *型の変数へのポインタは[ ]型 このような[ ]に入る語句が分からないです。 教えて下さい!!

  • ポインタ

    long ToLittleEndian(char *a,long bytesize){ long i; char lb; char hb; long lsize; lsize=bytesize/2; for (i=0;i<lsize;i++){ hb=*(a++); lb=*(a--); *(a++)=lb; *(a++)=hb; } return 0; } ポインタのアドレスがはみだすとどうなるのでしょうか? 上記のようなコードの場合、最後の処理でポインタaが1バイト分はみ出してしまいますが、 存在しないアドレスを参照しようとするとエラーになるかと思いますが ポインタを動かすだけだと問題ないのでしょうか? 処理系やコンパイラに依るのでしょうか。 初心者ですがよろしくお願いします。

  • C++ 文字列とポインタ、STL::mapについて

    C++でポインタと文字列の受け渡しについて質問です。 MyData::search()は文字列を受け取ってメンバ変数 dict内の ヒットしたデータの グループ(文字列)を返すメンバ関数です。 メンバ変数 dict はSTLのmapを使っています。 void MyData::search( const char* funcbox, const char* result ){ for ( map<const char*, const char*>::iterator itr = dict.begin(); itr != dict.end(); ++itr ){ const char* a_name = itr->first; const char* a_group = itr->second; if ( strstr( a_name, funcbox) ){ result = a_group; return; } } result = NULL; } MyData::dict["yamada"] = "groupA"; const char* res = NULL; MyData::search("yamada", res); cout << " group = " << res << endl; 上のようにアクセスするとメンバ関数内では res == "groupA" となりますが、 関数から出るとresはNULLになってしまいます。 res に関数を抜けた後も消えないアドレスを渡すにはどうすればよいでしょうか?

  • ポインタ変数とポインタのポインタ

    ポインタ変数の宣言 char *a[]; をしたとき僕の中では a[0],a[1]...という、ある文字列A,B,C...の最初のアドレスを指すポインタが、配列になっているものを宣言していると理解していました。 しかしこの次に、ポインタのポインタが出てきました。僕はこれを、 ある変数を指し示すアドレスのアドレスである、と理解しました。 この2つは1つめはいくつかのアドレスを指し示すもの、2つ目は1つのアドレスを指し示すものであるとして、僕の中で異なったものであると理解していましたが、参考書「C標準コースウェア」によると プログラムにおいて、関数でポインタ配列を受け取るときchar *p[]はchar **pとしてもよい と書かれており、またその実例として、 (9-5) #include <stdio.h> void disp (char *p[],int n){ int i; for (i= 1;i<n;i++){ printf("%s\n",p[i]); } } int main(void){ char *girl[] = {"Arica","Candy","Lisa"}; disp (girl,sizeof(girl)/sizeof(girl[0])); return 0; } というプログラムが書かれていました。 ここで一気に訳が分からなくなりました。 char *girl[] = {"Arica","Candy","Lisa"}; と宣言されているため、 girl[0]はAricaという文字列の最初のアドレスを指すポインタ、 *girl[0]はAricaという文字列を直接指し示していると解釈しています。 girlは{"Arica","Candy","Lisa"}という文字列の配列の最初のアドレスを指し示していると考えました。 sizeof(girl)を使った時に不思議なのですが、 girlはどのように配列の終わりを理解しているのでしょうか? (配列の要素数を渡していない点が不思議です。) また、 disp側が受け取ったのは*girl[]であり、いくつかのポインタの配列ですが、渡したものはgirlという要素数がないポインタ1つだけです。 そして最初の疑問が出てくるわけですが、*p[]を**pと書きかえてみると、 文字列のアドレスを示すgirlという名の1つのポインタを渡すと、pという名のポインタのポインタで受け取るというのも、よくわからなくなっています。 おそらくポインタ配列に対する理解がどこかでずれているようですが、自分でどこがわからないのかわからなくなっています。 どうかご教授ください。

  • C言語 ポインターと文字列

    C言語の勉強をしており、その途中でよく分からない挙動に出くわしたので 原因を知りたく、投稿しました。 よく分からない挙動と言うのは ポインターで作った文字列表示の際に for(i=0; *(str+i) != '\0'; i++) としてfor文を抜ける様にしたのですが、最後まで表示した後に セグメントエラーになってしまいます。 真ん中の文がおかしいのかと思い、単体で printf("%c", *(str+1)) や printf("%c", *(str+i)) (iには適当な数字を入れて) 表示したのですがセグメントエラーにはなりませんでした。 また、下の様に手書きの場合とfor文で回した場合でプログラムを作って試したのですが、 手書きの方はエラーは出ず、for文だとエラーがでました。 これはfor文の仕様なのでしょうか? 分かる方がいらっしゃったら教えて頂けるとありがたいです。 ちなみにパソコンは MacOSX10.6 コンパイラはXcodeを落とした時に入手できるもの i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3) Copyright (C) 2007 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. を使用しました。 int i; char *name; name = "test"; printf("name: %s\nadd: %p\n", name, &name); printf("by hand\n"); printf("%c\n%p\n",*(name+0), (name+0)); printf("%c\n%p\n",*(name+1), (name+1)); printf("%c\n%p\n",*(name+2), (name+2)); printf("%c\n%p\n",*(name+3), (name+3)); printf("%c\n%p\n",*(name+4), (name+4)); printf("with for\n"); for (i = 0; i < 4; i++) { printf("%c\n%p\n",*(name+i), (name+i)); }

  • CHAR型ポインタについて。

    CHAR型ポインタについて。 当方C言語初心者です。 ポインタと文字列の関係分からないことが出てきました。 参考にしている本があり、そのページに下記のソースで「const char *pc1」のポインタ変数を用意して、そこに直接文字列を代入しています。 本来、「char *pc1」はchar型のアドレスを格納するための変数のはずなのに、その変数に文字列を代入してることに疑問を感じました。 この記述の仕方は間違っていないのでしょうか?また、アドレスを格納するための変数「*pc1」に「abcdefg」の文字列はどのようにメモリ上で格納されているのでしょうか? 知ってどうなるの?みたいな質問かもしれませんが、ご教授いただけると幸いです。 #include <stdlib.h> #include <string.h> void func(void) { const char *pc1 = "abcdefg"; //←ココ char *pc2 = (char *)malloc( strlen(pc1) +1); if ( pc2 ) { strcpy( pc2, pc1 ); free( pc2 ); } }

  • 文字列の宣言(ポインタと配列)

    Cでソケット通信などはできるくらい(もちろんできると言っても私のレベルで) になりましたが、文字列を宣言する際に char *str = "ahaha'; char str[] = "ahaha"; の2種類の違いが今イチしっくりきません。 いろんな参考書でこれの説明はありましたが、でも結局なんなんだ、という感じです。 ポインタで宣言するべき時、配列で宣言するべきときが判断できません。 またポインタで宣言するとエラーが出るけど試し配列で宣言してみたら なんか知らんが動いた、ということも多々ありましたが理由がよくわからなかったです。 よろしくお願いいたします。

  • printfの引数指定でなぜ文字列ポインタがOK?

    C言語初心者です。現在入門的書籍の1冊目を読んで勉強中です。VBAは経験あります。 printf関数について質問です。 引数の指定で通常  printf("書式文字列", 変数で値) のようにしていしますよね。  char a = 'A';  printf("%c", a); ←ここで変数aの値の「A」を渡している と理解しています。 上の例で、書式文字列を省略し、  printf(a); だとエラーがでます。 しかし、文字列の場合  char a[] = "ABC";  printf(a); はエラーにならず、「ABC」と出力されます。 さらに、ポインタを使用して  char a[] = "ABC";  char *b = a;  printf(b); もエラーにならず、上と同様に「ABC」と出力されます。 まず、この2つの例で、エラーとならず、書式文字列が省略できているのが不思議です。 これが書式文字列を省略しているわけではないとするならば、 「printf(a)」=「printf(b)」=「printf("ABC")」ということになりますが、 「printf(a)」のaも「printf(b)」のbも"ABC"の先頭のアドレスを示しているんですよね。 ということは、printf関数の引数の指定方法は  printf(書式文字列 または 文字列の先頭アドレス, 変数) というように考えられるのですが、認識があっているでしょうか? そもそも文字列について、VBAでは文字と文字列の区別はなにも意識せずに扱えたのでやや戸惑っているのですが、C言語では文字列の場合は宣言時に  char a[] のように宣言し、あとは先頭のアドレスで文字列を使っていくという感じなのでしょうか? 初心者なもので何が理解できていないのかもよくわからない状況で、質問がわかりづらいかもわかりませんが、よろしくお願いします。

  • 文字列をポインタに入れる方法を教えてください。

    どなたか文字列をポインタに入れる方法を教えてください。下のプログラムのa=count(name1);とreverse(name1,name2,a);のとこにエラーが表示されます。ちなみに&を入れてもダメでした。整数の場合は&を入れたらできるみたいですが、文字列となるとやり方が違うのでしょうか? 問題としてはローマ字で名前を入力して表示し、文字数と名前を逆順にする2つの関数countとreverseを各自定義してそれぞれ定義しプログラムを組みなさい。姓と名の間は1文字空白を入れ、空白は文字数に含めないこと。 下のプログラムを実行させると・・・ 名前を入力しなさい。 yamada hirosi //自分で入力 yamada hirosi 文字数は12 逆順にした後はisorih adamay となるはずなんですが、なりません。どなたか宜しくお願いします。 #include "stdafx.h" #include <stdio.h> int count(char *name1[]) { int i,b=0; for(i=0;*name1[i]!='\0';i++) { b++; } b--; return b; } void reverse(char *name1[],char *name2[],int a) { int w; for(w=0;w<=a;w++) { *name2[w]=*name1[a-w]; } *name2[w]='\0'; } int main(int argc, char* argv[]) { char name1[80],name2[80]; int a; printf("名前を入力しなさい\n"); gets(name1); printf("%s\n",name1); a=count(name1); printf("文字数は%d\n",a); reverse(name1,name2,a); printf("逆順にした後は%s\n",name2); return 0; }