1

構造体とファイルでプログラムを作成しようとしています。以下は私のコードの一部です(プログラム全体ではありません)。私がやろうとしているのは、ユーザーにコマンドを書くように依頼することです。例えば。ジョンを削除します。John James 5000 ipad購入に入る。

問題は、構造体要素の「引数」を保存するためにコマンドを分割したいことです。それが私がstrtokを使った理由です。しかし、これらを構造体に「配置」する人について、別の問題に直面しています。また、「args」を安全な方法で構造体に「渡す」方法は、非常に奇妙に思えます。(ユーザーからの) すべての入力をバイナリ ファイルに保存するためです。

strcpy(catalog[0]->short_name, args[1]); 

短い名前が構造体の最初の要素に保存される時が来たからです。しかし、ファイルが書き込まれたらどうなるでしょうか? 最初の要素が存在するので ..[0] と書くと 私はそれについて書きますか?私は何をすべきか?助けてくれてありがとう!:D

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100

char command[1500]; 

struct catalogue                
{
        char short_name[50];
        char surname[50];
        signed int amount;
        char description[1000];
}*catalog[MAX]; 

int main ( int argc, char *argv[] )
{
    int i,n;
    char choice[3];

    printf(">sort1: Print savings sorted by surname\n");
    printf(">sort2: Print savings sorted by amount\n");
    printf(">search+name:Print savings of each name searched\n");
    printf(">delete+full_name+amount: Erase saving\n");
    printf(">enter+full_name+amount+description: Enter saving \n");
    printf(">quit:  Update + EXIT program.\n");

    printf("Choose your selection:\n>");
    gets(command);                     //it save the whole command

    /*in choice it;s saved only the first 2 letters(needed for menu choice again)*/
    strncpy(choice,command,2);      
    choice[2]='\0';                   

char** args = (char**)malloc(strlen(command)*sizeof(char*));
memset(args, 0, sizeof(char*)*strlen(command));

char* temp = strtok(command, " \t");

for (n = 0; temp != NULL; ++n)
{   
    args[n] = strdup(temp);
    temp = strtok(NULL, " \t");
    printf(" %s ",args[n]);
}

strcpy(catalog[0]->short_name, args[1]);         //segmentation fault
strcpy(catalog[0]->surname,args[2]);
catalog[0]->amount=atoi(args[3]);               //atoi doesn't work
strcpy(catalog[0]->description,args[4]);


}

その結果、プログラムを実行した後、次の行でセグメンテーション違反が発生します。

strcpy(catalog[0]->short_name, args[1]); 

何か助けはありますか?何か案は?

4

4 に答える 4

4

2つのエラーがあります:

  1. あなたのcatalog[MAX]配列はあなたMAXへのポインタを保持していますstruct catalogueが、それらのどれも初期化されていません。これを修正する方法は、ポインタとして宣言しないか、malloc必要に応じて次のように宣言することです。catalog[0] = (struct catalogue *)malloc(sizeof(struct catalogue));

  2. あなたのargs変数は悪いです。まず、コマンド文字列の長さと同じ長さの文字列の配列を作成するつもりはないと思います。つまり、「sort1」と入力すると、が作成されますargs[5]。コマンドの長さは、必要な引数の数とは関係がないため、これは無意味です。

    ただし、本当にそれを実行したい場合は、配列用のスペースを作成しますが、配列内の文字列用のスペースは作成しません。そのため、最終的にはセグメンテーション違反が発生します(ただし、取得しているのは上記の#1によるものです)。使用するときに、各要素にスペースを割り当てる必要がありargsます。

コードは次のようになります。

for (n = 0; temp != NULL; ++n)
{
   args[n] = (char *)malloc((strlen(temp) + 1) * sizeof(char));
   strcpy(args[n], temp);
   // and so on
}
于 2010-05-14T14:14:14.267 に答える
1

catalougeの配列は、オブジェクトの配列ではなく、ポインターの配列ですが、これらのポインターは何にも初期化されていないため、セグメンテーション違反が発生します

試す:

struct catalogue                 
{ 
        char short_name[50]; 
        char surname[50]; 
        signed int amount; 
        char description[1000]; 
}catalog[MAX]; 



strcpy(catalog[0].short_name, args[1]);         //segmentation fault  
strcpy(catalog[0].surname,args[2]);  
catalog[0].amount=atoi(args[3]);               //atoi doesn't work  
strcpy(catalog[0].description,args[4]); 
于 2010-05-14T14:13:27.950 に答える
1

このコードには多くの問題があります。

まず第一に、入力行の引数の数とカタログ内のエントリの数を混同しています。あるコンテキストではn、引数の数をカウントするために使用していますが、別のコンテキストでは、それを使用してcatalog配列にインデックスを付けています。

必要のないメモリ管理の頭痛の種を作成しています。変数は完全に不要であり、argsとにかくメモリを間違って割り当てています。あなたは基本的に、「 のすべての文字にchar へのポインターを割り当てますがcommand、これはおそらくあなたが望むものではありません.

すっぽんぽんargs_ あなたはそれを必要としません。

これがプログラム全体ではないことは承知していますが、通常の配列ではなく catalog、ポインターの配列として作成している理由が明確ではありません。struct catalog

回線で何をしていると思うかわかりません

*catalog[n]->short_name=*args[1]; 

式の型catalog[n]->short_namechar[50]. このコンテキストでは、配列型は暗黙的にポインター型に変換 (「減衰」) されますchar *。したがって、式全体の型は、整数型で*catalog[n]->short_nameある* (char *)、または単なる plaincharです。args[1]基本的に、 の最初の文字の値を の最初の文字に代入しようとしていますcatalog[n]->short_name

catalog[n]意味のある場所を指すように初期化されていないため、とにかくこれは問題ではありません。segfault は、ランダムな場所を指している short_nameを暗黙的に逆参照するメンバーにアクセスしようとすることから発生しています。catalog[n]

=次に、代入演算子を使用して文字列データを代入することはできません。strcpy()またはを使用する必要がありますstrncpy()

最後に、NEVER NEVER NEVER NEVER NEVER use gets(). コードに障害点が発生しますC99 で公式に廃止されたため、使用しないでください。fgets()代わりに使用してください:

if (fgets(command, sizeof command, stdin) != NULL)
{
  char *newline = strchr(command, '\n');
  if (newline != NULL)
    *newline = 0;
}

コマンド文字列を解析し、フィールドを構造体のメンバーに割り当てる必要がある方法は次のとおりです。

curToken = strtok(command, '\t');
if (curToken)
  strncpy(catalog[n]->short_name, curToken, sizeof catalog[n]->short_name);

curToken = strtok(NULL, '\t');
if (curToken)
  strncpy(catalog[n]->surname, curToken, sizeof catalog[n]->surname);

curToken = strtok(NULL, '\t');
if (curToken)
{
  char *chk;
  catalog[n]->amount = (int) strtol(curToken, &chk, 10);
  if (!isspace(*chk) && *chk != 0)
    fprintf(stderr, 
      "Warning: expected integer value for amount, received %s instead\n",
      curToken);
}

curToken = strtok(NULL, '\t');
if (curToken)
  strncpy(catalog[n]->description, curToken, sizeof catalog[n]->description);

catalogこのコードは、がまだポインターの配列として宣言されており、各要素が意味のある場所を指すように初期化されていることを前提としています。それ以外の場合は、宣言を からstruct catalog {...} *catalog[MAX];struct catalog {...} catalog[MAX]変更し、 に変更->.ます。

于 2010-05-14T14:43:29.450 に答える
1

forループは一度に 1 つの引数を割り当てますが ( ) args[n] = ...、各パスで複数の引数にアクセスします: *args[1]args[2]など。これらは最初のパスでは初期化されません。

警告は別のバグによるものです。そのような配列にポインタを割り当てることはできません。strcpy()代わりに使用してください。

于 2010-05-14T13:17:55.223 に答える