char型のポインタの配列

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
slei

char型のポインタの配列

#1

投稿記事 by slei » 14年前

それなりに演習を経ても未だにポインタがいまいち理解できず、またしても課題に詰まってしまったので質問させてもらえないでしょうか。
第一引数で与えられた名前のファイルを読み込み、ファイルの先頭から7行までを読み込み、7行を超えた場合は読み込みを打ち切り読み込んだ行を標準出力に出力し、7行に満たない場合はそれまで読み込んだすべての行を標準出力に出力する、というプログラムを組みたいのですが
コンパイルは通るものの、実行するとセグメンテーション違反のエラーが発生してしまいます。デバッガのメッセージを見るに、アドレスと思われる値が入っていることが確認できるのでポインタやメモリ確保といった辺りに問題があることは想定できるのですがその部分の理解が足りず問題点をうまく見つけることができません。このプログラムでは、読み込んだ各行の長さにあわせてmalloc()でメモリ領域を確保することが条件として設けられています。どうかアドバイスをいただけないでしょうか。よろしくお願いします。

コード:

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

#define MAXLEN 100

int main(char *argv[])
{
  FILE *fp; /* ストリームポインタ */
  int len; /* 文字列の長さを取得*/
  char tmp[MAXLEN]; /* 取得文字列の一時置き場 */
  int i = 0; /* カウンタ1 */
  int ii; /* カウンタ2 */
  char *str[7]; /* 文字列取得ポインタを7つ用意 */

  fp = fopen(argv[1], "r"); /* 第1引数のファイルを開く */
  if(fp == NULL){
    printf("Can't open file: %s.\n", argv[1]);
    return -1;} /* 開けなかった場合エラーを返して終了 */

  while(fgets(tmp,MAXLEN,fp) != NULL || i > 7){ /* ファイルの終わりか7回繰り返すまで */
    strlen(tmp); /* 文字列の長さ取得 */
    str[i] = (char*)malloc(sizeof(char) * len + 1); /* 文字列の長さ+\0分のメモリ取得 */

    if(str[i] == NULL){
      printf("malloc error.\n");
      return -1;} /* 取得失敗の場合エラーを返して終了*/

    strcpy(str[i],tmp); /* 取得した文字列を確保したメモリに移す */
    i++;
  }

  if(i == 7)
    printf("%s\n", str[6]); /* 7列をこえて終了した場合最後の行のみ表示 */
  else{
    for(ii = 1; ii == i; ii++)
      printf("%s\n",str[ii]);} /* その前に終了した場合取得した行を表示 */

  fclose(fp);
  i = 0;
  while(i == 7){
    free(str[i]);
    i++;}
  free(str); /* ファイルを閉じてメモリを解放 */

  return 0;
}
(デバッガに通したログ)
(gdb) run fruits_list.txt
Starting program: rep4-2 fruits_list.txt

Program received signal SIGSEGV, Segmentation fault.
0x00000000004006ad in main ()
(gdb)

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: char型のポインタの配列

#2

投稿記事 by bitter_fox » 14年前

slei さんが書きました:

コード:


int main(char *argv[])
{
  FILE *fp; /* ストリームポインタ */
  int len; /* 文字列の長さを取得*/
  char tmp[MAXLEN]; /* 取得文字列の一時置き場 */
  int i = 0; /* カウンタ1 */
  int ii; /* カウンタ2 */
  char *str[7]; /* 文字列取得ポインタを7つ用意 */

  while(fgets(tmp,MAXLEN,fp) != NULL || i > 7){ /* ファイルの終わりか7回繰り返すまで */
    strlen(tmp); /* 文字列の長さ取得 */
    str[i] = (char*)malloc(sizeof(char) * len + 1); /* 文字列の長さ+\0分のメモリ取得 */
  }

  else{
    for(ii = 1; ii == i; ii++)
      printf("%s\n",str[ii]);} /* その前に終了した場合取得した行を表示 */

  i = 0;
  while(i == 7){
    free(str[i]);
    i++;}
}
幾つか問題がありますね。
1.strlen(tmp)の戻り値を受け取っていない。(mallocで使われているlenに代入するべきではないでしょうか?)
2.ループの終了判定が全体的に逆に指定してしまっています。
while (・・・)及びfor(; ・・・; )は・・・である間実行します。
ですので、
while (略 || i > 7)は「ファイルの終わりかiが7より大きい間」となり、
for (ii = 1; ii == i; ii++)も「iiがiと同じ値の間」となってしまいます。(その次のwhileも同様)

slei

Re: char型のポインタの配列

#3

投稿記事 by slei » 14年前

げふん・・・・・・相変わらず私はつまらないミスを連発しますね
lenの代入を忘れてたのは書き込んだ後に気がついたのですが、ループ指定が逆になっていたのは素で見落としていました・・・・・・

non
記事: 1097
登録日時: 15年前

Re: char型のポインタの配列

#4

投稿記事 by non » 14年前

int main(int argc, char* argv[])
じゃ、ないでしょうか。それに最後の
free(str); /* ファイルを閉じてメモリを解放 */
はいらないかな。
non

slei

Re: char型のポインタの配列

#5

投稿記事 by slei » 14年前

ループ式を重点的に見直したところ正常に動作するようになりました、ご迷惑おかけしました・・・・・・
こういう初歩的な部分のミスって本当に多いんですよね私・・・・・・
ただポインタ部分の理解が足りないというのは事実なのでそこも含めて改めて勉強したいと思います。

コード:

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

#define MAXLEN 100

int main(int argc, char *argv[])
{
  FILE *fp; /* ストリームポインタ */
  int len; /* 文字列の長さを取得*/
  char tmp[MAXLEN]; /* 取得文字列の一時置き場 */
  int i = 0; /* カウンタ1 */
  int ii; /* カウンタ2 */
  char *str[7]; /* 文字列取得ポインタを7つ用意 */

  fp = fopen(argv[1], "r"); /* 第1引数のファイルを開く */
  if(fp == NULL){
    printf("Can't open file: %s.\n", argv[1]);
    return -1;} /* 開けなかった場合エラーを返して終了 */

  while(fgets(tmp,MAXLEN,fp) != NULL){ /* ファイル終わりまで */
    len = strlen(tmp); /* 文字列の長さ取得 */
    str[i] = (char*)malloc(sizeof(char) * len + 1); /* 文字列の長さ+\0分のメモリ取得 */

    if(str[i] == NULL){
      printf("malloc error.\n");
      return -1;} /* 取得失敗の場合エラーを返して終了*/

    strcpy(str[i],tmp); /* 取得した文字列を確保したメモリに移す */
    i++;
    if(i == 7)
      break; /* 7行で打ち切る */
  }

  if(i < 7){
    for(ii = 0; ii < i; ii++)
      printf("%s\n",str[ii]);} /* その前に終了した場合取得した行を表示 */
  else{
    printf("%s\n", str[6]);} /* 7列をこえて終了した場合最後の行のみ表示 */

  fclose(fp);
  i = 0;
  while(i < ii){ /* mallocで確保した分を判断して開放 */
    free(str[i]);
    i++;}

  return 0;
}

閉鎖

“C言語何でも質問掲示板” へ戻る