2

最初に char** 姓と char** を出力すると、奇妙な出力が得られます。malloc を正しく実行しているのか、それとも何か他のことを間違って実行しているのかはわかりません。

入力 -> names1.txt

出力

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

int main ()
{
  int size, i;
  char **surname, **first, *middle_init, dummy, str[80];
  FILE *fp_input = fopen("names1.txt", "r");

  fscanf(fp_input, "%d%c", &size, &dummy); // gets size of array from file

  /* dynamic memory allocation */

  middle_init = (char*)malloc(size * sizeof(char));
  surname = (char**)malloc(size * sizeof(char*));
  first = (char**)malloc(size * sizeof(char*));

  for (i = 0; i < size; i++)
  {
    surname[i] = (char*)malloc(17 * sizeof(char));
    first[i] = (char*)malloc(17 * sizeof(char));  
  } // for

  /* reads from file and assigns value to arrays */

  i = 0;
  strcpy(middle_init, "");

  while (fgets(str, 80, fp_input) != NULL)
  { 
    surname[i] = strtok(str, ", \n");
    first[i] = strtok(NULL, ". ");
    strcat(middle_init, strtok(NULL, ". "));
    i++;
  } // while

  /* prints arrays */      

  for (i = 0; i < size; i++)
        printf("%s %s\n", surname[i], first[i]);

  return 0;
} // main
4

2 に答える 2

1

コードをざっと見てみると、次のことが示唆されます。

  • で見つかった文字列を姓などstrcpy()にコピーするには、テーマで またはバリアントを使用する必要があります。strtok()

  • あなたが書いた方法では、割り当てられたメモリを捨てます。

  • surnameおよび配列に行を保持するために使用する文字列へのポインターを格納しているため、繰り返し出力が得られfirstます。その文字列は、印刷を行うときに最後の行のみを保持します。これと前のポイントは、最初のポイントの結果です。

  • ミドルネームのイニシャルには 1 文字だけを割り当てます。次に、strcat()それらを文字列として扱うために使用します。他の名前と同じように、ミドルネームのイニシャルを文字列として扱うことをお勧めします。または、それらを印刷する必要がないため、ミドルネームのイニシャルを完全に無視することにするかもしれません.

  • 代わりに 17 を使用するenum { NAME_LENGTH = 17 };か、同等のものを使用することはお勧めできません。

間違いなく他の問題もあります。

あなたはまだ研究の過程で構造に達していないと思います。構造体をカバーしている場合は、おそらく構造体型を使用して完全な名前を表し、並列配列の代わりに名前の単一配列を使用する必要があります。これにより、メモリ管理も簡素化される可能性があります。構造体で固定サイズの配列要素を使用するため、名前ごとに 1 つの割り当てを行うだけで済みます。

以下のコードは、出力を生成します。

Ryan Elizabeth
McIntyre O
Cauble-Chantrenne Kristin
Larson Lois
Thorpe Trinity
Ruiz Pedro

このコードでは、err_exit()エラー報告を 4 行の段落ではなく 1 行の呼び出しにするため、この関数は非常に価値があります。つまり、エラー チェックを行う可能性が高くなります。これは可変長引数リストの基本的な使い方で、まだ理解していないかもしれませんが、非常に便利で強力です。エラーチェックできるがそうでない唯一の関数はfclose()andprintf()です。ファイルを読んでいる場合、チェックするメリットはほとんどありませんfclose()。書き込み中にfclose()失敗した場合は、ディスク容量が不足しているか、そのようなことが原因である可能性があり、おそらくエラーを報告するのが適切です。<errno.h>ヘッダーのリストに追加して、レポートすることができerrnoますstrerror(errno)エラー報告をさらに改善したい場合。コードは割り当てられたメモリを解放します。valgrindクリーンな健康状態をもたらします。

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

static void err_exit(const char *fmt, ...);

int main(void)
{
    enum { NAME_SIZE = 25 };
    const char *file = "names1.txt";
    int size, i;
    char **surname, **first, str[80];
    FILE *fp_input = fopen(file, "r");

    if (fp_input == NULL)
        err_exit("Failed to open file %s\n", file);
    if (fgets(str, sizeof(str), fp_input) == 0)
        err_exit("Unexpected EOF on file %s\n", file);
    if (sscanf(str, "%d", &size) != 1)
        err_exit("Did not find integer in line: %s\n", str);
    if (size <= 0 || size > 1000)
        err_exit("Integer %d out of range 1..1000\n", size);

    if ((surname = (char**)malloc(size * sizeof(char*))) == 0 ||
        (first = (char**)malloc(size * sizeof(char*))) == 0)
        err_exit("Memory allocation failure\n");
    for (i = 0; i < size; i++)
    {
        if ((surname[i] = (char*)malloc(NAME_SIZE * sizeof(char))) == 0 ||
            (first[i] = (char*)malloc(NAME_SIZE * sizeof(char))) == 0)
            err_exit("Memory allocation failure\n");
    }

    for (i = 0; i < size && fgets(str, sizeof(str), fp_input) != NULL; i++)
    { 
        char *tok_s = strtok(str, ",. \n");
        char *tok_f = strtok(NULL, ". ");
        if (tok_s == 0 || tok_f == 0)
            err_exit("Failed to read surname and first name from: %s\n", str);
        if (strlen(tok_s) >= NAME_SIZE || strlen(tok_f) >= NAME_SIZE)
            err_exit("Name(s) %s and %s are too long (max %d)\n", tok_s, tok_f, NAME_SIZE-1);
        strcpy(surname[i], tok_s);
        strcpy(first[i], tok_f);
    }
    if (i != size)
        err_exit("Only read %d names\n", i);

    fclose(fp_input);

    /* prints arrays */      
    for (i = 0; i < size; i++)
        printf("%s %s\n", surname[i], first[i]);

    for (i = 0; i < size; i++)
    {
        free(surname[i]);
        free(first[i]);
    }
    free(surname);
    free(first);

    return 0;
}

static void err_exit(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    exit(1);
}
于 2012-11-11T07:02:21.177 に答える