我正在試驗鏈表并試圖更好地理解指標。我試圖從檔案中獲取資料到鏈表。我的 file.txt 看起來像這樣:
&&&
Carl
18
male
&&&
John
22
male
&&&
Jessica
19
female
&&&
Brandon
33
male
&&&
Ema
23
female
我希望它正確加載到鏈表。此外,條目數顯示 1 個條目,并且僅列印一次。
我的代碼:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <math.h>
#define DATABASE_FILE "./file.txt"
#define BUFFER_SIZE 255
struct info {
char name[50];
char age[99];
char sex[99];
struct info *next;
};
typedef struct info info_t;
void load_linked_array(info_t **head) {
FILE *file;
char buffer[BUFFER_SIZE];
int counter = 0, number_entries = 0;
info_t *ptr = NULL, *current = NULL;
file = fopen(DATABASE_FILE, "r");
if (!file) { printf("Couldnt read data.!\n"); return; }
while (fgets(buffer, BUFFER_SIZE, file) != NULL) {
switch (counter ) {
case 0:
ptr = (info_t *)malloc(sizeof(info_t *));
if (!ptr) {
printf("Nepodarilo sa alokovat pamat!\n");
return;
}
break;
case 1:
strcpy(ptr->name, buffer);
ptr->name[sizeof(ptr->name)-1] = '\0';
break;
case 2:
strcpy(ptr->age, buffer);
ptr->age[sizeof(ptr->age)-1] = '\0';
break;
case 3:
strcpy(ptr->sex, buffer);
ptr->sex[sizeof(ptr->sex)-1] = '\0';
break;
case 4:
ptr->next = NULL;
if (*head == NULL) {
*head = ptr;
current = ptr;
} else {
current->next = ptr;
current = current->next;
}
number_entries ;
}
}
printf("Loaded %d entries.\n", number_entries);
fclose(file);
}
void print_linked_array(info_t **head) {
if (!head) { return; }
if (head != NULL) {
info_t *ptr;
ptr = *head;
if (ptr != NULL) {
printf("Name: %s", ptr->name);
printf("Age: %s", ptr->age);
printf("Sex: %s\n", ptr->sex);
ptr = ptr->next;
}
}
}
我嘗試過類似這樣的計數器:
case 4:
ptr->next = NULL;
if (*head == NULL) {
*head = ptr;
current = ptr;
} else {
current->next = ptr;
current = current->next;
}
number_entries ;
counter = 0;
}
}
它加載了 4 個條目而不是 5 個,并且只列印了一次 {這是我的終端}:
load
Loaded 4 entries.
print
Name: Carl
Age: 18
Sex: male
uj5u.com熱心網友回復:
首先,你永遠不會重置你的計數器。因此,在閱讀案例 4 后,它會查找案例 5、案例 6、7、8。
每個條目有四行,但您有五個案例。第一個條目將起作用,它將讀取其四行,但隨后case 4它將讀取下&&&一個條目并且下一個條目將被關閉。
&&& 0
name 1
age 2
sex 3
&&& 4
name 0
age 1
sex 2
&&& 3
*head僅當它為空時才分配給。如果不是,則永遠不會分配給它,也不會看到任何作業。
你只為一個指標分配了足夠的空間,你需要分配整個結構。
print_linked_array 不回圈,只會列印第一個元素。
有了這些修復,它應該可以作業。還有幾個問題。
- 您沒有檢查是否有足夠的空間來存盤各個欄位。使用
strdup來代替。 - 該檔案在函式內部進行了硬編碼。
- 這不是雙指標的好用法。
- 使用現有的
BUFSIZ.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// You can typedef and declare a struct in one statement.
typedef struct info {
// Store pointers rather than arbitrary size strings.
// Saves memory and allows any size fields.
char* name;
char* age;
char* sex;
struct info* next;
} info_t;
// Have a function to consistently allocate and initiate your structs.
// Avoids reading garbage or walking off the end of the list.
// (Also have one to delete it and free its fields.)
info_t *info_new() {
// Allocate the complete struct, not a pointer to the struct.
info_t *info = malloc(sizeof(info_t));
info->next = NULL;
info->name = NULL;
info->age = NULL;
info->sex = NULL;
return info;
}
// Pass in the file, do not hard code it.
// Return the new array. This is not a good use of a double pointer.
info_t *info_load(const char *file) {
int counter = 0, number_entries = 0;
FILE *fp = fopen(file, "r");
if (!fp){
// perror prints a decent error message with why it failed.
perror(file);
}
// Store the head, keep the tail to work on.
info_t *tail = NULL;
info_t *head = NULL;
// Use the existing BUFSIZ constant for your I/O buffers.
char buffer[BUFSIZ];
while (fgets(buffer, BUFSIZ, fp) != NULL){
switch(counter ){
case 0:
if( !tail ) {
// First iteration, the tail is the head.
tail = info_new();
head = tail;
}
else {
// Subsequent iterations, make a new tail and add it to the old tail.
tail->next = info_new();
tail = tail->next;
}
// We just added an entry, immediately increment the number of entries.
number_entries ;
break;
case 1:
// strdup() will allocate the correct amount of memory and copy the string.
tail->name = strdup(buffer);
break;
case 2:
tail->age = strdup(buffer);
break;
case 3:
tail->sex = strdup(buffer);
// Last field, reset the counter.
counter = 0;
break;
default:
// Put in a guard against walking off the case.
fprintf(stderr, "should not reach the default case");
exit(1);
}
}
printf("Loaded %d entries.\n", number_entries);
fclose(fp);
return head;
}
// No need for a double pointer to just read the list.
void info_print(info_t *head) {
// Loop until you hit a null.
for( info_t *info = head; info != NULL; info = info->next ) {
printf("Name: %s", info->name);
printf("Age: %s", info->age);
printf("Sex: %s\n", info->sex);
}
}
int main() {
info_t *info = info_load("file.txt");
info_print(info);
}
uj5u.com熱心網友回復:
代碼中存在一些主要問題:
ptr = (info_t *)malloc(sizeof(info_t *));為指標分配空間,而不是為結構分配空間。你應該寫:ptr = (info_t *)malloc(sizeof(*ptr));這個錯誤會導致未定義的行為,你奇跡般地沒有觀察到。
ptr->name[sizeof(ptr->name)-1] = '\0';如果字串比目標短,則無用,否則已發生未定義的行為。使用它來去除換行符并安全地復制字串:snprintf(ptr->name, sizeof(ptr->name), "%.*s", (int)strcspn(buffer, "\n"), buffer);您應該擺脫
case 4:新節點應在存盤sex成員后直接鏈接,并且counter必須重置為0. 這會導致每個元素讀取 5 行,從而破壞串列的內容。在
print_linked_array您應該使用while回圈而不是if (ptr != NULL). 這會導致最多列印一個元素。print_linked_array不需要接收雙指標,直接傳遞head指標即可。*head在錯誤和/或空檔案的情況下未初始化。如果分配錯誤,檔案不會關閉。
這是一個修改后的版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <math.h>
#define DATABASE_FILE "./file.txt"
#define BUFFER_SIZE 255
struct info {
char name[50];
char age[99];
char sex[99];
struct info *next;
};
typedef struct info info_t;
void load_linked_array(info_t **head) {
FILE *file;
char buffer[BUFFER_SIZE];
int counter = 0, number_entries = 0;
info_t *ptr = NULL, *current = NULL;
file = fopen(DATABASE_FILE, "r");
/* always set the head pointer for error and empty file cases */
*head = NULL;
if (!file) {
printf("Couldnt read data.!\n");
return;
}
while (fgets(buffer, BUFFER_SIZE, file) != NULL) {
size_t len = strlen(buffer);
if (len > 0 && buffer[len - 1] == '\n')
buffer[--len] = '\0';
switch (counter ) {
case 0:
ptr = (info_t *)malloc(sizeof(*ptr));
if (!ptr) {
printf("Nepodarilo sa alokovat pamat!\n");
fclose(file);
return;
}
break;
case 1:
snprintf(ptr->name, sizeof(ptr->name), "%s", buffer);
break;
case 2:
snprintf(ptr->age, sizeof(ptr->age), "%s", buffer);
break;
case 3:
snprintf(ptr->sex, sizeof(ptr->sex), "%s", buffer);
ptr->next = NULL;
if (*head == NULL) {
*head = ptr;
} else {
current = current->next = ptr;
}
current = ptr;
number_entries ;
counter = 0;
}
}
if (counter != 0) {
/* free partially filled node */
free(ptr);
}
printf("Loaded %d entries.\n", number_entries);
fclose(file);
}
void print_linked_array(const info_t *head) {
while (head != NULL) {
printf("Name: %s", head->name);
printf("Age: %s", head->age);
printf("Sex: %s\n", head->sex);
head = head->next;
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/373381.html
標籤:C
上一篇:根據第二行對二維陣列進行排序
