2016-10-31 4 views
1

Я просмотрел свой код часами, и я просто не могу понять, почему он не работает. Эта программа создает список покупок с использованием динамического массива. Я могу добавить новые элементы просто отлично. Я также могу сохранять и читать элементы из файла. Моя проблема в том, что всякий раз, когда я читаю из файла, а затем добавляю новый элемент, мой массив перепутался, а моя функция печати печатает мусор. Что нужно делать, так это то, что всякий раз, когда я загружаю файл или добавляю новый элемент, он должен всегда добавлять его в конец списка. Вот мой код:Динамический массив печатает мусор после добавления элементов

typedef struct ShoppingList { 
    int id; 
    char name[100]; 
    int amount; 
    char unit[10]; 
}ShoppingList; 

void PrintShoppingList(ShoppingList *list, int *itemsLoaded) 
{ 
    if (*itemsLoaded == 0) { 
     printf("Inköpslistan är tom.\n"); 
     return; 
    } 
    for (int i = 0; i<*itemsLoaded; i++) { 
     printf("%d\t %s\t\t %d\t %s\n", list[i].id, list[i].name, list[i].amount, list[i].unit); 
    } 
} 

void AddNewItem(ShoppingList *list, int *itemsLoaded) { 
    ShoppingList *temp; 
    printf("Namn på vara: "); 
    scanf_s("%s", list[*itemsLoaded].name, sizeof(list[*itemsLoaded].name)); 
    printf("Antal: "); 
    while (scanf_s("%d", &list[*itemsLoaded].amount) != 1) { 
     scanf_s("%*s"); 
     printf("Antal: "); 
    } 
    printf("Enhet: "); 
    scanf_s("%s", list[*itemsLoaded].unit, sizeof(list[*itemsLoaded].unit)); 
    list[*itemsLoaded].id = *itemsLoaded; 
    temp = (ShoppingList*)realloc(list, (*itemsLoaded + 2) * sizeof(ShoppingList)); 
    if (temp != NULL) { 
     list = temp; 
     *itemsLoaded = *itemsLoaded + 1; 
     printf("Vara lades till.\n"); 
    } else { 
     //free(list); 
     printf("Kunde inte allokera minne.\n"); 
    } 
} 

void SaveShoppingListToFile(ShoppingList *list, int *itemsLoaded) { 
    if (*itemsLoaded == 0) { 
     printf("Inköpslistan är tom. Kan ej spara.\n"); 
     return; 
    } 
    char filename[20]; 
    int i; 
    printf("Spara fil som: "); 
    scanf_s("%s", filename, sizeof(filename)); 
    FILE *fp; 
    fopen_s(&fp, filename, "w"); 
    if (fp) 
    { 
     fprintf(fp, "%d", *itemsLoaded); 
     for (i = 0; i<*itemsLoaded; i++) { 
      fprintf(fp, "\n%s\n%d\n%s", list[i].name, list[i].amount, list[i].unit); 
     } 
     fclose(fp); 
     printf("Fil sparad.\n"); 
    } else { 
     printf("Kunde ej spara filen.\n"); 
    } 
} 

void LoadShoppingListFromFile(ShoppingList *list, int *itemsLoaded) { 
    char filename[20]; 
    int nEntries = 0; 
    ShoppingList *temp; 
    printf("Läs in fil: "); 
    scanf_s("%s", filename, sizeof(filename)); 
    FILE *fp; 
    fopen_s(&fp, filename, "r"); 
    if (fp) 
    { 
     fscanf_s(fp, "%d", &nEntries); 
     for (int i = 0; i<nEntries; i++) { 
      fscanf_s(fp, "%s", list[*itemsLoaded].name, sizeof(list[*itemsLoaded].name)); 
      fscanf_s(fp, "%d", &list[*itemsLoaded].amount); 
      fscanf_s(fp, "%s", list[*itemsLoaded].unit, sizeof(list[*itemsLoaded].unit)); 
      list[*itemsLoaded].id = *itemsLoaded; 
      temp = (ShoppingList*)realloc(list, (*itemsLoaded + 2) * sizeof(ShoppingList)); 
      if (temp != NULL) { 
       list = temp; 
       *itemsLoaded = *itemsLoaded + 1; 
      } else { 
       //free(list); 
       printf("Kunde inte allokera minne.\n"); 
      } 
     } 
     fclose(fp); 
     printf("Fil inläst.\n"); 
    } else { 
     printf("Kunde ej läsa filen.\n"); 
    } 
} 

void Menu() { 
    int menu = 0, *itemsLoaded, index = 0; 
    itemsLoaded = &index; 
    ShoppingList *list = NULL; 
    list = (ShoppingList*)malloc(sizeof(ShoppingList)); 
    if (list != NULL) { 
     do 
     { 
      system("CLS"); 
      menu = 0; 
      printf("%d\n", *itemsLoaded); 
      printf("Meny\n 1 - Lägg till en vara till inköpslistan\n 2 - Skriv ut inköpslistan\n 3 - Skriv inköpslistan till fil\n 4 - Läs in inköpslista från fil\n 5 - Ändra vara\n 6 - Ta bort vara\n 7 - Avsluta\nAnge Val: "); 
      while (scanf_s("%d", &menu, sizeof(int)) != 1) { 
       scanf_s("%*s"); 
       printf("\nFelaktigt val. Försök igen.\n"); 
       printf("Ange Val: "); 
      } 
      if (menu < 7) { 
       switch (menu) { 
        case 1: 
         AddNewItem(list, itemsLoaded); 
         PrintShoppingList(list, itemsLoaded); 
         break; 
        case 2: 
         PrintShoppingList(list, itemsLoaded); 
         break; 
        case 3: 
         SaveShoppingListToFile(list, itemsLoaded); 
         break; 
        case 4: 
         LoadShoppingListFromFile(list, itemsLoaded); 
         PrintShoppingList(list, itemsLoaded); 
         break; 
       } 
      } else if (menu > 7 || menu < 1) { 
       printf("Felaktigt val. Försök igen."); 
      } 
      system("pause"); 
     } while (menu != 7); 
    } else { 
     printf("Kunde inte allokera minne."); 
    } 
    free(list); 
} 

int main() { 
    Menu(); 
    return 0; 
} 
+4

Попробуйте использовать ваш отладчик! Многие современные IDE позволяют запускать код за строкой, и вы увидите, где именно происходит ошибка. Если вы все еще не знаете, где проблема, пожалуйста, уменьшите свой код и разместите только соответствующие части. Никто не хочет читать целые 200 строк кода. –

+0

Что касается стиля и простоты использования, я нашел лучше иметь 'numItems = * itemsLoaded' в начале каждой функции и' * itemsLoaded = numItems' непосредственно перед возвратом. Это помогает в обработке. Также напечатайте 'numItems' перед тем, как вы выведете свой список, чтобы убедиться, что вы его правильно обновляете. – sabbahillel

+0

Я использовал свой отладчик, и это после моей системы («пауза»); в меню, где разбивается массив. Каждый раз, когда я добавлял элемент или читал из файла, я печатаю список, и это хорошо, однако, когда он проходит мимо этой паузы, он прерывается, и когда я пытаюсь добавить или прочитать его сбой и печать, я получаю мусор. – FaderKerm

ответ

0

Функция void AddNewItem(ShoppingList *list, int *itemsLoaded) { перераспределяет list когда массив заполнен, но указатель на вновь выделенный массив никогда не передается обратно вызывающим, который по-прежнему использует предыдущее значение. Это вызывает неопределенное поведение.

Вы должны передать адрес указателя, чтобы функция могла обновить значение вызывающего абонента.

int AddNewItem(ShoppingList **listp, int *itemsLoaded) { 
    ShoppingList *list = *listp; 
    printf("Namn på vara: "); 
    scanf_s("%s", list[*itemsLoaded].name, sizeof(list[*itemsLoaded].name)); 
    printf("Antal: "); 
    while (scanf_s("%d", &list[*itemsLoaded].amount) != 1) { 
     scanf_s("%*s"); 
     printf("Antal: "); 
    } 
    printf("Enhet: "); 
    scanf_s("%s", list[*itemsLoaded].unit, sizeof(list[*itemsLoaded].unit)); 
    list[*itemsLoaded].id = *itemsLoaded; 
    list = (ShoppingList*)realloc(list, (*itemsLoaded + 2) * sizeof(ShoppingList)); 
    if (list != NULL) { 
     *listp = list; 
     *itemsLoaded = *itemsLoaded + 1; 
     printf("Vara lades till.\n"); 
     return 1; // success 
    } else { 
     //free(list); 
     printf("Kunde inte allokera minne.\n"); 
     return 0; // failure 
    } 
} 

Вызов этой функции из main() как AddNewItem(&list, itemsLoaded);

Обратите внимание, что это было на самом деле проще перераспределять массив перед разборе дополнительный элемент. Для этого подхода исходный указатель может быть NULL.

Функция LoadShoppingListFromFile имеет ту же проблему.

+0

Это работает, кроме Мне нужно было изменить список покупок ** list = * listp; в ShoppingList * list = * listp; Удивительное спасибо за помощь! – FaderKerm

+0

@FaderKerm: мой плохой, я обновил ответ. – chqrlie