Структуры, стрток, сегментация разломов - PullRequest
1 голос
/ 14 мая 2010

Я пытаюсь сделать программу со структурами и файлами. Следующее - только часть моего кода (это не вся программа). Я пытаюсь сделать следующее: попросить пользователя написать свою команду. например. удалить Джона например. введите покупку John ipad 5000 ipad.

Проблема в том, что я хочу разделить команду, чтобы сохранить ее 'args' для элемента структуры. Вот почему я использовал strtok. НО я сталкиваюсь с другой проблемой в том, кто "помещает" их в структуру Кроме того, мне кажется довольно странным, как «передавать» аргументы в структуру безопасным способом, так как я сохраняю все входы (от пользователя) в двоичном файле, который может быть повторно открыт и переписан, поэтому я не могу использовать:

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 голосов
/ 14 мая 2010

У вас есть 2 ошибки:

  1. Ваш массив catalog[MAX] содержит MAX указатели на ваш struct catalogue, но ни один из них не инициализирован. Способ исправить это - либо не объявлять их указателями, либо malloc использовать их по мере необходимости, как в catalog[0] = (struct catalogue *)malloc(sizeof(struct catalogue));

  2. Ваша переменная args неверна. Во-первых, я не думаю, что вы намереваетесь создать массив строк, длина которых равна длине вашей командной строки. Это означает, что если вы введете «sort1», вы создадите args[5]. Это бессмысленно, потому что длина вашей команды не имеет никакого отношения к тому, сколько аргументов она должна иметь.

    Но если вы действительно хотите это сделать, вы создаете пространство для массива, но не для строк в массиве. В любом случае, в конечном итоге вы получите segfault (хотя тот, который вы получаете, из-за # 1 выше) из-за этого. Вам необходимо выделить место для каждого элемента в args, как вы его используете.

Код может выглядеть так:

for (n = 0; temp != NULL; ++n)
{
   args[n] = (char *)malloc((strlen(temp) + 1) * sizeof(char));
   strcpy(args[n], temp);
   // and so on
}
1 голос
/ 14 мая 2010

Много проблем в этом коде.

Прежде всего, вы путаете количество аргументов в строке ввода для количества записей в каталоге. В одном контексте вы используете n для подсчета количества аргументов, но в другом вы используете его для индексации массива catalog.

Вы создаете головные боли при управлении памятью там, где вам это не нужно. Переменная args совершенно не нужна, и вы все равно выделяете для нее память неправильно. Вы в основном говорите: «выделите указатель на символ для каждого символа в command, что, вероятно, не то, что вы хотите.

Потерять args полностью; тебе это не нужно.

Я понимаю, что это не вся ваша программа, но не ясно, почему вы создаете catalog как массив указателей на struct catalog, а не просто обычный массив.

Я не уверен, что вы думаете, что делаете на линии

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

Тип выражения catalog[n]->short_name равен char[50]. В этом контексте тип массива неявно преобразуется («распадается») в тип указателя, char *. Таким образом, тип целого выражения *catalog[n]->short_name равен * (char *) или просто char, который является целым типом. По сути, вы пытаетесь присвоить значение первого символа args[1] первому символу catalog[n]->short_name.

Всё равно это не имеет значения, потому что catalog[n] не был инициализирован, чтобы указывать куда-либо значимое; segfault происходит от попытки доступа к элементу short_name, который неявно разыменовывает catalog[n], который указывает куда-то случайно.

Далее, вы не можете использовать оператор присваивания = для назначения строковых данных; Вы должны использовать strcpy() или strncpy(), чтобы сделать это.

Наконец, НИКОГДА НИКОГДА НЕ НИКОГДА НИКОГДА НИКОГДА использовать 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] и измените -> на ..

1 голос
/ 14 мая 2010

ваш массив для catalouge - это массив указателей, а не массив объектов, но эти указатели ни к чему не инициализированы, поэтому ошибка seg

попробовать:

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]); 
1 голос
/ 14 мая 2010

Цикл for назначает один аргумент за раз (args[n] = ...), но затем обращается к нескольким аргументам на каждом проходе: *args[1], args[2] и т. Д., Которые не инициализируются при первом проходе.

Предупреждение связано с другой ошибкой. Вы не можете просто назначить указатель на такой массив. Вместо этого используйте strcpy().

...