#c
#c
Вопрос:
Мне нужно создать таблицу различных продуктов и их питания в зависимости от их веса и калорий, т. Е. Яблоко 4 унции 50 калорий. Массив объявляется автоматически, и первые 2 элемента явно инициализируются. Затем я должен перебирать оставшиеся продукты, которые должны быть введены пользователем, исходя из числа, которое я ввел в макрос LUNCH_QTY. В цикле мне нужно сохранить входные данные во временный символьный буфер и сохранить вес и калории непосредственно в структуре. Затем определите точную длину имени продукта и динамически выделите точный объем памяти, определенный на предыдущем шаге, и сохраните указатель на него в элементе name структуры. Я НЕ МОГУ использовать calloc или realloc. Поэтому я использовал malloc. Если динамическое выделение завершается неудачно, мне нужно вывести ошибку, используя stderr. И если это сработает, мне нужно скопировать имя продукта в динамически выделяемую память с помощью memcpy. После завершения цикла for я создаю таблицу и освобождаю динамически выделяемую память.
Моя проблема в том, что когда я выполняю цикл, я зависаю в операторе «if» на последней итерации. Кажется, что он все еще выполняет цикл, но затем он выбивает меня из отладчика. Может быть, у меня проблемы с указателями, и я получаю доступ к недоступной памяти? Idk, но любая помощь будет высоко оценена. Я новичок в C, поэтому любая информация была бы отличной. Заранее спасибо. Ниже приведен код.
PS. таблица неполная, и я не знаю, будут ли еще работать распределения таблиц, потому что я еще не смог зайти так далеко, также я еще не освободил память, и я не знаю, так ли это сделано.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LUNCH_QTY 4
#define INIT_ELEM 2
#define BUFF_LENGTH 128
struct Food
{
char *name; //"Name" attribute of food
int weight, calories; //"Weight" and "Calories" attributes of food
}lunches[LUNCH_QTY] = {[0] = {"Apple", 4, 100}, [1] = {"Salad", 2, 80}};
int main()
{
for (int StructCnt = INIT_ELEM; StructCnt < LUNCH_QTY; StructCnt )
{
printf("Please input a foods name, weight, and calories all space"
" separated: ");
char NameBuff[BUFF_LENGTH]; //Temporary Character Buffer if this was done correctly?
scanf("%s %d %d", NameBuff, amp;lunches[StructCnt].weight,
amp;lunches[StructCnt].calories);
//Get name length for memory allocation
int NameLength = strlen(NameBuff);
//Find length of food name
int NameLength = strlen(NameBuff);
//If dynamic allocation fails output an error
if ((lunches[StructCnt].name = malloc(NameLength 1)) == NULL)
{
fprintf(stderr,"Error - String Name Was Inputted Incorrectly");
return(-1);
}
memcpy(lunches[StructCnt].name, NameBuff, sizeof(NameBuff));
}
//Print out food names, weight, and calories in order of the structure
//and then free the memory once name is printed out
printf("n LUNCH MENU"
"nFOOD WEIGHT CALORIES"
"n-----------------------------n");
int PrintCnt = 0;
while (PrintCnt < LUNCH_QTY)
{
printf("%-15s M Mn", lunches[PrintCnt].name,
lunches[PrintCnt].weight, lunches[PrintCnt].calories);
PrintCnt ;
}
//Free all dynamically allocated memory
int FreeCnt = 0;
while (FreeCnt < LUNCH_QTY)
{
free(lunches[PrintCnt].name);
PrintCnt ;
}
return 0;
}
Комментарии:
1.
malloc(NameLength * sizeof(char))
->malloc((NameLength 1) * sizeof(char))
. Вам нужно на один символ больше для завершения строки NUL. Это очень распространенная ошибка, которую мы видим здесь. Кстатиmalloc(NameLength 1)
,(char*)
приведение бесполезно иsizeof (char)
равно 1 по определению. Однако могут быть и другие проблемы2. Привет @Jabberwocky, я реализовал то, что вы сказали: if ((lunches[StructCnt].name = malloc(NameLength 1)) == NULL) { fprintf(stderr, «Ошибка — имя строки было введено неправильно»); break; } но я получаю ту же проблему, что и при зависании напоследняя итерация цикла for в этом операторе? есть идеи?
3.
memcpy(lunches[StructCnt].name, NameBuff, sizeof(NameBuff));
должно быть `memcpy(lunches[StructCnt].name, NameBuff, NameLength 1);, however it would be better to replace the sequence from malloc through memcpy with
lunches[StructCnt].name = strdup(NameBuff);` или, по крайней мере, заменить memcy наstrcpy(lunches[StructCnt].name, NameBuff);
4. @mevets это помогло, спасибо вам за это. И мы вынуждены использовать memcpy в этом назначении.
5. последний вопрос для всех вас, как мне освободить память для всех имен, которые я использовал, будет ли это что-то вроде free (lunches-> names) или что-то подобное, и мне придется перебирать каждое имя, или есть одна строка, которая освобождает всю память имен, в этомструктура?
Ответ №1:
Здесь вы выделяете NameLength 1
байт:
lunches[StructCnt].name = malloc(NameLength 1));
Но здесь вы копируете sizeof(NameBuff)
(= 128) байт:
memcpy(lunches[StructCnt].name, NameBuff, sizeof(NameBuff));
Вместо этого вы хотите это:
memcpy(lunches[StructCnt].name, NameBuff, NameLength 1);
или даже лучше:
strcpy(lunches[StructCnt].name, NameBuff);
Кроме того, в последнем цикле while вы пытаетесь освободить первые два элемента массива, хотя они не были выделены динамически с помощью malloc
.
Вам нужно это:
PrintCnt = INIT_ELEM; // free elements 2 and 3 and leave
// elements 0 and 1 alone
while (PrintCnt < LUNCH_QTY)
{
free(lunches[PrintCnt].name);
PrintCnt ;
}
Также вы должны использовать for
циклы, которые здесь более уместны (вы уже использовали цикл for для ввода).
for (int count = 0; count < LUNCH_QTY; count )
{
printf("%-15s M Mn", lunches[count].name,
lunches[count].weight, lunches[count].calories);
}
//Free all dynamically allocated memory
for (int count = INIT_ELEM; count < LUNCH_QTY; count )
{
free(lunches[count].name);
}
Имейте в виду, что ваш дизайн подвержен ошибкам, это очень плохая идея иметь динамически выделяемую память, а не динамически выделяемую память в одном и том же массиве.