こんにちは(こんばんわ?)。
わたしは某大学の学生です。
現在課題のためにプログラムを制作中なのですが、
どうしてもエラーが消えなくて困っています。
提出期限がすでに切れているので、大至急お答え願います!たすけてー!

エラー内容:セグメンテーション違反
     (実行時のみ、コンパイルエラーはなし)
エラー箇所(多分):strcmpの使い方?

ソース(一部):
(前略)
int Lookup(char *p[],char buffer[])
{
int i;

for(i=0;i< parray_size;i++)
if(!strcmp(p[i],buffer))
break;

if(i== parray_size)return 0;
else return 1;
}

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

A 回答 (5件)

1. #include <string.h> は入っていますか?


 今回は問題ないけど、引数が間違っていたりするときに参考になるので、入れておいた方が無難ですよ。

2. parray_size はちゃんと p のサイズになっていますか?
 というか、どこで宣言していますか?
 これがp の配列数より大きいと質問のようなエラーになりそうです。

3. この関数(Lookup)を呼んでいる箇所のソースが欲しいです。
 そっちで間違っている可能性のほうがありそう。

4. とりあえず、下記のような感じで動くことを確認しました。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int parray_size = 3;

int
main(void) {

 static char *p[3] = { "ほげ", "ふが", "もげ" };
 char buffer[10];

 printf ("%d\n", Lookup(p, "ない"));
 printf ("%d\n", Lookup(p, "ほげ"));

}

int Lookup(char *p[],char buffer[])
{
 int i;

 for (i=0;i< parray_size;i++) {
  if (!strcmp(p[i],buffer)) {
   break;
  }
 }

 if (i== parray_size) {
  return 0;
 }
 else {
  return 1;
 }
}

この回答への補足

1.string.hは入ってます。

2.parray_sizeはプリプロセッサで、
  #define parray_size 10000
  の様に、定義しています。

3.これが呼び出し部分です。
  /*(前略)*/  
void main(void)
{
  char *p[parray_size];
  char buffer[parray_size];
  /*(中略)*/  
  printf("What's a word to lookup? ");
  
  scanf("%s",buffer);
  
  if(Lookup(p,buffer))
    printf("%s is exist.\n\n", buffer);
  else printf("%s is not exist.\n\n", buffer);
}

補足日時:2002/01/16 22:08
    • good
    • 0
この回答へのお礼

tailkuppaさん回答ありがとう御座いました!
問題のほうはめでたく解決しました!
サンプルのほう、とっても役に立ちました。
ではでは~。

お礼日時:2002/01/17 01:44

下の者ですが、大ボケをかましてしまいました。


>2の対策ですが、strncmpという関数がありますので、ご検討下さい。
これですが、buffer の大きさをstrlenで求めて(これを例えば、buf_sizeとします)、
for(i=0;i< parray_size;i++)

for(i=0;i< parray_size-buf_size;i++)
にすればOKですね…

後、parray_sizeも同様にstrlenで求めた方が安全ですね^^;
速度が重要でなければ、strlenで計算する方をおすすめします。
strlenも\0で終了している必要がありますのでご注意を
    • good
    • 0

セグメンテーション違反 は確保した範囲外のメモリにアクセスした場合におこります。



このプログラムで、考えられるのは

 1. parray_size が p 用に確保されたサイズより大きく、ループ内で、p[i] が範囲外をさしている
 2. strcmp は、いずれかが、'\0' まで探索をします。
つまり、このプログラムで、pもしくは、bufferの末尾に'\0'が含まれていなければ、探索は範囲外に及ぶ
 3. p、buffer のいずれかに、NULL が渡されている。

の可能性です。
1の対策は、他の部分を見ないことには、、、
2の対策ですが、strncmpという関数がありますので、ご検討下さい。
3の対策は、関数の最初にポインタのチェックを加えることです。

まず、どの箇所で、落ちているのかを確認してください。
fprintf(stderr, ".."); // .. には何か好きなメッセージ
で、ポイントポイントで、メッセージを出力し、何処まで表示されたかを確認するのが簡単で、効果的な方法です。

以上、簡単ですが。

参考URL:http://www.linux.or.jp/JM/html/LDP_man-pages/man …
    • good
    • 0

質問のソースを見た限りでは何も言えないし、tailkuppaさまのプログラムならエラーがないと思われるので、ちょっと余談を。



char *p[]
という引数の定義ですが、このように書くように推奨されてはいるものの、意味があいまいになりかねないので
char **p
を私はオススメします。
どちらも同じ表現ですが、人間から解釈すると前者は配列のポインタを渡し、後者はポインタのポインタを渡すと解釈できます。
しかし、実際に内部では、ポインタのポインタが渡されているのです。

焦っているのに余談なんて失礼しました。
配列とポインタは似通っていて、ポインタを要求されるところでは配列を渡すことができる場合が多いのですが、多次元になるとそれが通用しない場合があります。
二次元配列、ポインタの配列、配列のポインタ、ポインタのポインタ、これらは混同しやすいので微妙に使い分けることが重要です。

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

はぽるんさん回答ありがとう御座いました!
問題のほうはめでたく解決しました!

tailkuppaさんのサンプルを元に試行錯誤。
その結果、今まで*p[]の初期化に

  for(i=0;i < parray_size;i++)
   p[i]=NULL;

のようにヌルポインタを使っていたものを、

  for(i=0;i < parray_size;i++)
   p[i]="\0";

の様にしたらスッパリ解決しました。
………なんででしょ?(笑)
はぽるんさんはポインタに詳しいんですよね?

結局strcmpはあんまり関係なかったようです…
んー…Cは奥が深いっす。
それではこのへんで~。

お礼日時:2002/01/17 01:45

このソースの内容自体には、おかしいところは無いと思います。


Lookup()を呼び出している個所とのインタフェースか、または
実引数の定義部分の問題でしょう。
    • good
    • 0
この回答へのお礼

ranxさん回答ありがとう御座いました!
問題のほうはめでたく解決しました!

いつかまた自分の質問(救援信号ともいう)を見つけたら
その時はまた宜しくお願いします!
では失礼をば♪♪

お礼日時:2002/01/17 01:44

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

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

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 行が収まりそうな長さなだけ。

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; は可能。)つまり...続きを読む

Qint main(int argc, char* argv[]) についての質問

こんにちは.つね日ごろ思っている質問させてください.
Cの参考書には,
(1)
void main(void)
{
}

(2)
int main(int argc, char* argv[])
{
return 0;
}
の2つのパターンが記載されていますが,
どういう違いがあるのでしょうか?

(1)の場合main関数は,型を持たず,引数も持たない.
※Turbo Cなどのコンパイラーでは,
return文がないと警告出ます.
(2)の場合は,int 型をかえし,引数はint型 変数と char型ポインタ配列(?)
を指定している.
といったくらいしか分かりません.

(2)に関してもう少し述べれば,
コマンドラインからファイルを指定し,実行することが
できると勉強した記憶があるのですが,
理解があいまいです.

特に(2)の場合のmain関数の意味と,その使い方について
アドバイスお願い致します.

Aベストアンサー

> (1)
> void main(void)
  ...
> (2)
> int main(int argc, char* argv[])
  ...
> の2つのパターンが記載されていますが,どういう違いがあるのでしょうか?

(1) は、間違いです。少なくとも ANSI-C の規格に合致していません。

main() は、特別な関数で、ANSI-C の規格では以下の三通りのうちのどれか
でなくてはいけない、と定められています。

int main(void)
int main(int argc, char *argv[]);
int main(int argc, char *argv[], char *envp[]);

因みに三番目の形式では、三つ目の引数には環境変数が入ります。
以下のようなコードで確認ができます。

int main(int argc, char *argv[], char *envp[])
{
  int i = 0;
  while (envp[i]) {
    printf("envp[%d] = '%s'\n", i, envp[i]);
    ++i;
  }
  return 0;
}


> ※Turbo Cなどのコンパイラーでは,return文がないと警告出ます

Turbo C は、規格に厳格なのでしょう。返り値が void なのはおかしいので、
int だとみなすよ、という警告も出てるはず。で、int が帰り値だとみなし
ているので return が無いと、返り値が不定になるよ、と警告を出している
のでしょう。

> (1)
> void main(void)
  ...
> (2)
> int main(int argc, char* argv[])
  ...
> の2つのパターンが記載されていますが,どういう違いがあるのでしょうか?

(1) は、間違いです。少なくとも ANSI-C の規格に合致していません。

main() は、特別な関数で、ANSI-C の規格では以下の三通りのうちのどれか
でなくてはいけない、と定められています。

int main(void)
int main(int argc, char *argv[]);
int main(int argc, char *argv[], char *envp[]);

因みに三番目の形式では、三...続きを読む

Qchar型+char型ってint型? if(char型==int型)?

C言語の「汎整数拡張(インテグラルプロモーション)」というものに関するものだと思います。

char型とchar型を加えた結果は、char型でしょうか。それともint型でしょうか。
(下のプログラムの
printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */
という部分の結果は4なので、int型と考えるべきなのかな。)

私は、char型とint型の加算の結果はint型だと思っていましたが、
char型とchar型の加算の結果はやはりchar型だと思っていました。
(それが間違えているのでしょうか。)


if(a[0]==i) /* char型とint型の比較(?) */
の部分では、左辺はchar型、右辺はint型ですが、このように型の違う変数を比較しても文法上構わないのでしょうか。
(私は、「比較は必ず型の同じもの同士でしかできない」と思っていました。)
左辺はchar型のように見えて、じつはint型ですか。


#include <stdio.h>
int main(void)
{
char a[4];
int i=77;
printf("sizeof(int)は%d\n", sizeof(int));
printf("sizeof(char)は%d\n", sizeof(char));
printf("sizeof('M')は%d\n", sizeof('M'));
printf("sizeof(a[0])は%d\n", sizeof(a[0]));

a[0]='M';
a[1]=7+6;
a[2]=a[0]+a[1];
printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */
printf("sizeof(+a[0])=%d\n", sizeof(+a[0]));

if(a[0]==i) /* char型とint型の比較(?) */
puts("a[0]==i");
else
puts("a[0]!=i");

return(0);
}

ちなみにワーニングもエラーもなんにもでません。

C言語の「汎整数拡張(インテグラルプロモーション)」というものに関するものだと思います。

char型とchar型を加えた結果は、char型でしょうか。それともint型でしょうか。
(下のプログラムの
printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */
という部分の結果は4なので、int型と考えるべきなのかな。)

私は、char型とint型の加算の結果はint型だと思っていましたが、
char型とchar型の加算の結果はやはりchar型だと思っていました。
(それが間違えているのでしょう...続きを読む

Aベストアンサー

「sizeof 単項式」について補足です。

これは sizeof 演算子が「単項演算子」であるために書かれたものだと思われます。
例えば同様に単項演算子である ++ も、「++ 単項式」です。

では単項式とは何なのかというと、これは以下のようなものを指します。(抜けがあるかもしれませんが。)
・定数
・名前(変数名や関数名など)
・( 式 )
・後置式

( 式 ) はおなじみの「式の結果を返す」ものですが、実はこれ全体で単項式です。
本来「sizeof 単項式」では ( ) を必要としないので、sizeof より優先順位の低い演算子を含む式を裸で渡すことはませんが、( ) で囲めばどんな式でも書けるわけです。

後置式は「配列構文によるアドレス参照式」や「関数呼び出し式」、「メンバ参照式」「後置型インクリメント/デクリメント式」です。
なので、
> sizeof(a[0])
> と書いたら、[ ] という演算子は2項演算子だから、a[0]は単項式になっていない
は、わざわざ ( ) で囲まず sizeof a[0] と書いても、正しい単項式なので問題ありません。
(これらの演算子は、全て sizeof より優先順位が上になっています。)

先に ++ も単項式を取る、ということを書きましたが、++ だって
  ++*(p + n)
のような記述が通るのだから、sizeof でも問題がなくて当然です。

また、例えば ++ では「オペランドは左辺値でなければならない」という原則があり、左辺値でない式に ++ を適用するとコンパイルエラーが発生します。
しかし、sizeof に「オペランドはオブジェクトでなければならない」などという原則を聞いたことがありません。
無論コンパイルエラーも起きませんし、期待通りに式の値のサイズが返ります。
「式の値のサイズ」というのはコンパイル時に判明しているものなので、取得できて当然といえば当然ですが、これがCで定められた仕様かどうかというのは残念ながら見つけることはできませんでした。
ただし、質問にあるような sizeof の文法は全て正しく、警告が出ないのは仕様通りだというのは間違いありません。

「sizeof 単項式」について補足です。

これは sizeof 演算子が「単項演算子」であるために書かれたものだと思われます。
例えば同様に単項演算子である ++ も、「++ 単項式」です。

では単項式とは何なのかというと、これは以下のようなものを指します。(抜けがあるかもしれませんが。)
・定数
・名前(変数名や関数名など)
・( 式 )
・後置式

( 式 ) はおなじみの「式の結果を返す」ものですが、実はこれ全体で単項式です。
本来「sizeof 単項式」では ( ) を必要としないので、sizeof より優...続きを読む

Qfor(int i = 100, long n = 1; i > n/3i; i++)

for(int i = 100, long n = 1; i > n/3i; i++)
のように、初期設定で型の違う変数を宣言したいんだけど
C++ではこんなふうに2つ以上の型を宣言してはいけないんですか?

Aベストアンサー

,

コンマ演算子の原理です。
forの初期化文で "," で区切れるのは値を返す文だけです。
よってintステートメントもlongステートメントも値を返さないので、この文では使用できません。

というか、むしろ、intステートメントの第2引数としてlongが認識されてしまいます。
外で

int i; long n;

とし

for(i = 0, n = 0; hoge; hoge)

なら可能です。


人気Q&Aランキング

おすすめ情報