我创建了这个链表,但是我无法同时获取char数组和int。有什么建议?我一直在论坛和谷歌上下,但我似乎无法让它同意任何事情。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
int id;
char name[40];
struct node *next;
struct node *prev;
} info;
int insert (int num, char *Name);
void print ();
struct node *root; // Declare root a pointer to the first node
int main () {
int n, Id, i;
char nAme[40];
char *name_ptr;
root = NULL; // List is empty
printf ("How many list entries do you want to make?\n");
scanf (" %d ", &n);
n = 2;
for (i = 0; i < n; i++) {
printf ("Enter name: ");
fgets (nAme, 40, stdin);
printf ("Enter id number: ");
scanf ("%d", &Id);
name_ptr = &nAme[0];
insert (Id, name_ptr);
print ();
}
}
int insert (int num, char *Name)
{
// Get memory
struct node *temp = (struct node *) malloc (sizeof (struct node));
if (temp == NULL) {
printf ("Some malloc problem.\n");
return 1;
}
temp->id = num;
strcpy (temp->name, Name);
temp->next = root;
root = temp;
}
void print ()
{
struct node *temp = root;
while (temp != NULL) {
printf ("%d\n%s\n", temp->id, temp->name);
temp = temp->next;
}
printf ("\n");
}
很抱歉,我对这个网站有点新鲜,所以格式化可能会说javascript,但你可能会告诉它C。
答案 0 :(得分:0)
有许多问题密谋反对你。第一个,重要的,但不是显示停止,fgets
将读取直到并包括 newline
。这意味着您的所有nAme
(假设您的意思是name
)条目最后都有一个嵌入式换行符。当您尝试在列表中搜索或比较特定名称时,这会导致各种混乱。
一个很大的问题是,您无法确认是否收到要从用户添加到列表的输入。 始终,始终验证用户输入。这意味着至少要检查您实际上是否有存储输入。 e.g。
printf ("Number of list entries to make?: ");
if (scanf (" %d%*c", &n) != 1) {
fprintf (stderr, "error: invalid no. of entries.\n");
return 1;
}
for (i = 0; i < n; i++) {
printf ("Enter name: ");
if (!fgets (name, MAXC, stdin)) {
fprintf (stderr, "error: invalid name.\n");
return 1;
}
rmcrlf (name); /* strip trailing newline from name */
printf ("Enter id number: ");
if (scanf ("%d%*c", &id) != 1) {
fprintf (stderr, "error: invalid ID.\n");
return 1;
}
insert (id, name);
}
(注意: rmcrlf
(删除回车换行符)功能修剪尾随新行或从名称值返回错误的回车符。
对于您正在创建的列表类型(单/双链接,传统头/尾,循环,什么?)区别在于传统的 head / tail 将使用NULL
值来标记列表的结尾/开头,而循环 list将最后一个节点指向第一个允许从列表周围的任何点进行迭代的节点。
您似乎想要一个带有prev
和next
指针的双向链接列表,但您绝对不会尝试处理prev
指针无论如何。目前还不清楚您是否需要循环或 head / tail NULL
列表。无论您选择哪种方式,都必须考虑为每个prev
设置next
和insert
指针的值。无论您是在循环列表中设置1st
(和2nd
)还是与其余插入相比,都会有所不同。以下是插入函数的示例,它将正确处理循环列表的添加。头/尾NULL
列表不需要特定处理第二个节点。
struct node *insert (int num, char *name)
{
struct node *temp = malloc (sizeof *temp); /* allocate node */
if (!temp) {
fprintf (stderr, "error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
temp->id = num;
strcpy (temp->name, name);
if (!root) { /* empty list - insert first node */
temp->next = temp->prev = temp;
root = temp;
}
else if (root == root->next) { /* insert 2nd node */
temp->next = root;
root->prev = temp;
root->next = temp;
temp->prev = root;
}
else { /* insert all remaining nodes at end */
root->prev->next = temp;
temp->prev = root->prev;
temp->next = root;
root->prev = temp;
}
return temp;
}
(注意:函数类型为struct node *
。此处返回int
值几乎没用。您可以通过返回{{1来判断成功/失败如果发生故障,并且插入的节点可用于所需的任何插入后处理。此外, NOT 转换NULL
的返回值,您只需要取{ {1}}被指定的指针所指向的对象
请勿在代码中使用幻数。它们使代码难以维护。如果您需要常量来设置malloc
中的最大字符数,那么请使用sizeof
定义一个或设置全局name
以定义常量(例如#define MAXC 40
)。
将这些碎片放在一起并修复一些尼特,您可以编写双向链接循环列表,如下例所示。您可以通过简单地使用传统的 head / tail enum
列表来略微简化代码。
仔细查看代码并了解所做的更改(根本不需要enum { MAXC = 40 };
,并且在为{输入之后设置NULL
{1}}与name_ptr
)。另请注意n=2;
字符n
在输入缓冲区(例如scanf
)中的处理方式。如果您未考虑'\n'
,则会发现scanf
跳过输入,因为它会将输入缓冲区中的stdin
作为输入。
'\n'
示例使用/输出
scanf
内存使用/错误检查
在任何动态分配内存的代码中,对于分配的任何内存块,您都有2个职责:(1)始终保留指向起始地址的指针内存块,(2)当不再需要时,它可以释放。
必须使用内存错误检查程序,以确保您没有在已分配的内存块之外/之外写入,尝试读取或基于未初始化的值跳转,最后确认您已拥有释放了你分配的所有内存。对于Linux '\n'
是正常的选择。用法很简单,只需运行代码并检查结果:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXC 40
struct node {
int id;
char name[MAXC];
struct node *next;
struct node *prev;
} info;
struct node *insert (int num, char *name);
void print (void);
void delete_list (void);
void rmcrlf (char *s);
struct node *root; /* Declare root a pointer to the first node */
int main (void) {
int i, id, n;
char name[MAXC];
root = NULL; /* List is empty */
printf ("Number of list entries to make?: ");
if (scanf (" %d%*c", &n) != 1) {
fprintf (stderr, "error: invalid no. of entries.\n");
return 1;
}
for (i = 0; i < n; i++) {
printf ("Enter name: ");
if (!fgets (name, MAXC, stdin)) {
fprintf (stderr, "error: invalid name.\n");
return 1;
}
rmcrlf (name);
printf ("Enter id number: ");
if (scanf ("%d%*c", &id) != 1) {
fprintf (stderr, "error: invalid ID.\n");
return 1;
}
insert (id, name);
}
print();
delete_list();
return 0;
}
struct node *insert (int num, char *name)
{
struct node *temp = malloc (sizeof *temp); /* allocate node */
if (!temp) {
fprintf (stderr, "error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
temp->id = num;
strcpy (temp->name, name);
if (!root) { /* empty list - insert first node */
temp->next = temp->prev = temp;
root = temp;
}
else if (root == root->next) { /* insert 2nd node */
temp->next = root;
root->prev = temp;
root->next = temp;
temp->prev = root;
}
else { /* insert all remaining nodes at end */
root->prev->next = temp;
temp->prev = root->prev;
temp->next = root;
root->prev = temp;
}
return temp;
}
void print (void)
{
struct node *temp = root;
printf ("\n Id Name\n ---- ---------------------\n");
while (temp->next != root) {
printf (" %4d %s\n", temp->id, temp->name);
temp = temp->next;
}
printf (" %4d %s\n", temp->id, temp->name);
printf ("\n");
}
/* free memory for all nodes in list */
void delete_list (void)
{
struct node *temp = root->next;
while (temp != root) {
struct node *victim = temp;
temp = temp->next;
free (victim);
}
if (temp) free (temp);
}
/** stip trailing newlines by overwriting with null-terminating char.
* str is modified in place.
*/
void rmcrlf (char *s)
{
if (!s || !*s) return;
for (; *s && *s != '\n'; s++) {}
*s = 0;
}
始终确认释放所有堆块 - 不可能泄漏并且同样重要错误摘要:0个上下文中的0个错误。
查看更改,如果您有任何疑问,请询问。
答案 1 :(得分:-1)
什么不做?
查看代码:
root应初始化为NULL。
insert可以被称为惰性(Id,nName);插入的instread(Id,name_ptr);
在插入中,你应该初始化 - &gt; prev = NULL;