Jon McKee
malloc
выделяет блок неинициализированной непрерывной памяти запрошенного размера в байтах и передает обратно void*
указатель, так как он понятия не имеет, для чего вам нужна эта память.
Итак, как мы вычисляем, сколько байтов нам нужно тогда? Ну, в данном случае у нас есть массив символов, поэтому нам нужно пространство для каждого элемента (char
) и общий размер строки. Чтобы получить размер элемента, мы можем использовать sizeof(char)
Чтобы получить общий размер массива, мы можем использовать strlen(name) + 1
.
Это ваш код:
(char*)malloc(strlen(name)) //If name is "apple", strlen will return 5 (it doesn't include the termination character '\0'). See: http://www.cplusplus.com/reference/cstring/strlen/
Вы видите проблему? Если вы поставите точку останова на
printf
постройте и посмотрите на структуру lunches[2], вы увидите имя, за которым следует случайный мусор, потому что там нет символа нулевого завершения. Вот почему нам нужно, чтобы +1 на обоих
malloc
и
memcpy
чтобы выделить место для Терминатора строки и скопировать его, соответственно.
Кроме того, вам повезло, что размер
char
это один байт, в противном случае ваш
malloc
не будет выделять правильный размер. Вообще говоря, вы хотите, чтобы у вас вошло в привычку делать это так, как
malloc(sizeof(char) * (strlen(name) + 1))
. Это приведет к меньшим головным болям в будущем (а
char
это не всегда 1 байт). Однако "+1" не понадобится, например, с целочисленным массивом -
malloc(sizeof(int) * arraySize)
.
Однако это не имеет никакого отношения к вашей проблеме доступа к памяти. Это вызвано тем, что
free(name);
name = NULL;
Только ты
free
что вы
malloc
.
name
распределяется по стеку. Он будет отброшен, когда стековый фрейм будет выскочен при выходе функции. Это также, почему в строке
name = NULL;
должен показать ошибку в вашем компиляторе. Вы не можете повторно назначить
name
. Это не указатель на массив символов,
это массив символов- Ты это нарочно сделал
free
название структуры, но случайно ссылается на локальное имя вместо этого?
Ryan Thomsen
Большое вам спасибо за ваш ответ, он помог прояснить довольно много вещей на самом деле. Я чувствую, что следил за большинством ваших изменений, однако я изо всех сил пытаюсь выяснить некоторые ошибки. Я получаю предупреждение C6385,C6386 и 6054. Когда я запускаю программу, она никогда не проходит мимо ввода входных данных с помощью scanf. Может быть, я что-то сделал не так?
#define LUNCH_QTY 3
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
struct Food
{
char* name; int weight, calories;
} lunches[LUNCH_QTY] = {{(char*)"apple", 4, 100}, {(char*)"salad", 2, 80}};
for (int element = 2; element <= (LUNCH_QTY); element++)
{
char name[100];
printf("Please enter, space-separated, the name, weight and calories of a food: ");
if (scanf("%99s %d %d", name, &lunches[element].weight, &lunches[element].calories) == 1)
{
lunches[element].name = (char*)malloc(strlen(name)+1);
if (lunches[element].name)
{
memcpy(lunches[element].name, &name, strlen(name)+1);
}
else
{
fputs("Unable to allocate memory\n", stderr);
exit(1);
}
}
else
{
fputs("Unable to read input\n", stderr);
exit(1);
}
printf("%s %d %d", lunches[element].name, lunches[element].weight, lunches[element].weight);
free(lunches[element].name);
lunches[element].name = NULL;
}
}
Jon McKee
Это очень много измененного кода.
- Подумай об этом. for
петля тщательно, конкретно <=. Вы создаете 3 ланча (lunches[LUNCH_QTY]), но массивы индексируются нулем, так что общее количество обедов-это ланчи[3]?
Nvm, вы можете использовать только имя. scanf не имеет никаких проблем с простым использованием имени, как работает Пример Рика. Прошла минута с тех пор, как я пользовался хорошим Оле Си. Ваш оригинальный пример с моими изменениями работает нормально, и пример Рика ниже с моими заметками работает нормально, так что у вас есть два примера для работы :)