Есть несколько проблем с вашей программой.
То, что вы делаете, эквивалентно:
char data[SIZE];
char *p;
/* get some useful value in data */
p = data;
В контекст последней строки , data
относится к указателю, который указывает на первый элемент массива data
(то есть строка эквивалентна p = &data[0];
). Итак, вы просто присвоили указателю p
значение адреса первого символа в data
. Позже, когда вы изменяете содержимое из data
, указатель на первый элемент data
остается прежним (data
все еще существует в той же ячейке памяти). Итак, все ваши указатели ссылаются на одно и то же хранилище, и вы продолжаете перезаписывать содержимое хранилища.
Но тогда почему ваша программа работает, когда вы предоставляете буквенные строки? Потому что каждая литеральная строка в C гарантированно существует на протяжении всей жизни программы и имеет уникальный адрес. (Существует незначительное исключение: если вы используете литеральную строку в своей программе более одного раза, это может означать или не ссылаться на одну и ту же память.)
Итак, вы должны динамически распределять память для firstName
, lastName
и phoneNumber
членов ваших узлов и не забывать освобождать их, когда закончите с этим.
void addEntry(char *fn, char *ln, char *pn)
{
struct bookNode *tempNode, *iterator;
tempNode = malloc(sizeof *tempNode);
tempNode->firstName = malloc(strlen(fn) + 1); /* +1 for terminating 0 */
tempNode->lastName = malloc(strlen(ln) + 1);
tempNode->phoneNumber = malloc(strlen(pn) + 1);
/* Omitted check for malloc failures for brevity */
strcpy(tempNode->firstName, fn);
strcpy(tempNode->lastName, ln);
strcpy(tempNode->phoneNumber, pn);
/* Now continue with what you were doing */
}
Затем вам потребуется соответствующая freeEntry
функция для освобождения места.
Еще один способ сделать это - объявить ваш struct
иначе:
#define MAX 20
struct bookNode
{
char firstName[MAX];
char lastName[MAX];
char phoneNumber[MAX];
struct bookNode *next;
} *head;
Тогда вашей функции addEntry
не нужны вызовы malloc()
для firstName
, lastName
и phoneNumber
, но вам все равно нужно копировать данные, используя strcpy()
. (Чтобы узнать причину, перейдите по ссылке выше.) Ваша соответствующая функция freeEntry()
также не должна освобождать этих членов.
Теперь для остальной части вашей программы. Ваш способ найти завершающий символ новой строки работает, но вы можете упростить его, используя strchr()
стандартную функцию C. Вызов в вашем случае будет выглядеть так:
char *nl;
if ((nl = strchr(first, '\n')) != NULL) {
*nl = '\0';
}
Наконец, когда вы исправите все вышеперечисленное, вы обнаружите, что в вашей телефонной книге вы получаете последнюю запись дважды . В C feof()
не сообщает вам, находитесь ли вы в конце файла: он сообщает, что последняя попытка чтения из файла не удалась, потому что вы были в конце файла.