2010-05-14 3 views
1

Я пытаюсь создать программу с помощью структур и файлов. Следующее - это лишь часть моего кода (это не вся программа). Что я пытаюсь сделать: попросите пользователя написать его команду. например. удалите John например. войдите в покупку iPad John iPad 5000.Structs, strtok, segmentation fault

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

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

Поскольку настало время, краткое имя будет сохранено в первом элементе структуры. Но если файл написан, что происходит тогда? Первый элемент существует, поэтому, если я пишу .. [0] я напишу на нем? Что мне делать? Thanx заранее за любую помощь! : 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]); 


} 

В результате, после запуска программы я получаю Segmentation Fault ... для линии:

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

Любая помощь? Есть идеи?

+0

Я не программист на C, но в отношении вашего названия вопроса некоторые люди не любят людей, говорящих «help plz»: http://meta.stackexchange.com/questions/48024/what-is- up-with-all-always-say-plz-help –

+0

;) okkkk! hehehe thnx Andrew – FILIaS

ответ

1

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

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

+0

да, это правда, я попытался вывести его из цикла с каталогом [0] -> short_name. , но я получаю такое же предупреждение – FILIaS

+0

strcpy (каталог [0] -> short_name, args [1]); еще раз ... Ошибка сегментации , а если «args» - это число? atoi не работает! – FILIaS

+0

Уточните вопрос. –

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]); 
+0

Тонкий Некрополь! Это отличная помощь! : D – FILIaS

4

У вас есть 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

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

Прежде всего, вы вводите в заблуждение количество аргументов в строке ввода для количества записей в каталоге. В одном контексте вы используете 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] и смените -> на номер ..

+0

с использованием этого кода ... в строках: curToken = strtok (команда, '\ t'); curToken = strtok (NULL, '\ t'); curToken = strtok (NULL, '\ t'); curToken = strtok (NULL, '\ t'); Существует предупреждение: ПРЕДУПРЕЖДЕНИЕ: проходя аргумент 2 из «» strtok делает указатель из целого числа без броска Thnx за помощь в любом случае – FILIaS

+0

с помощью этого: символ * curToken = strtok (команда,»«); SEGMENTATION FOR LINE: strncpy (каталог [n] -> short_name, curToken, sizeof (каталог [n] -> short_name)); – FILIaS

+0

Crap; это должно быть «\ t» вместо «\ t»; Я был немного лишен сна. Что касается segfault, как я сказал выше, это предполагает, что 'catalog [n]' был правильно распределен и указывает где-то значимым. Как я уже сказал, непонятно, почему вы выделяете 'каталог' как массив * указателя * на' struct catalog', но я написал свой пример, предполагая, что это то, что вы хотели. Если нет, измените объявление из каталога 'struct ... * [MAX];' на 'struct ... catalog [MAX]' и используйте '.' для выбора компонента вместо' .'. –