我已经尝试并搜索了此问题。如果我尝试从列表中删除一个字符串,则会收到“ 3221225477”作为返回值。
我已经尝试使用其他方法,例如更改“返回值[];”在const char * del(ListNodePtr * strPtr,value [])函数中将“返回* value;”如果您能告诉我我应该在代码中进行哪些更改,将不胜感激。
这就是我定义结构的方式。我不知道这是否真的很好。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct listnode
{
char data[100];
listnode *nextPtr;
};
typedef struct listnode ListNode;
typedef ListNode *ListNodePtr;
这是插入函数:
void insert(ListNodePtr *strPtr, char value[])
{
ListNodePtr previousPtr, currentPtr, newPtr;
newPtr=(listnode*)malloc(sizeof(listnode));
strcpy(newPtr->data,value);
newPtr->nextPtr=NULL;
previousPtr=NULL;
currentPtr=*strPtr;
if(newPtr!=NULL)
{
while(currentPtr!=NULL &&
strcmp(currentPtr->data,value)<0)
{
previousPtr=currentPtr;
currentPtr=currentPtr->nextPtr;
}
if(previousPtr==NULL)
{
newPtr->nextPtr=*strPtr;
*strPtr=newPtr;
}
else
{
previousPtr->nextPtr=newPtr;
newPtr->nextPtr=currentPtr;
}
}else printf("%s was not inserted. Insuffiecient memory!",value);
}
这是“删除”功能:
const char *del(ListNodePtr *strPtr, char value[])
{
ListNodePtr previousPtr, currentPtr, tempPtr;
if(strcmp(value, (*strPtr)->data)==0) /*if the
first node shall be deleted*/
{
/*delete node*/
tempPtr=*strPtr;
*strPtr=(*strPtr)->nextPtr;
free(tempPtr);
return *value;
}
else
{
previousPtr=*strPtr;
currentPtr=(*strPtr)->nextPtr;
while(currentPtr!=NULL && strcmp(value,
currentPtr->data)!=0)
{
previousPtr=currentPtr;
currentPtr=currentPtr->nextPtr;
}
if(currentPtr!=NULL)
{
tempPtr=currentPtr;
previousPtr- >nextPtr=currentPtr->nextPtr;
free(tempPtr);
return *value;
}
}
return '\0';//if the node is not found
}
这是main()函数:
int main()
{
ListNodePtr startPtr;
startPtr=NULL;
int optiune;
char nume[100];
instructions();
printf("? ");
scanf("%d",&optiune);
while(optiune!=3)
{
switch(optiune)
{
case 1:
printf("Enter name:");
fflush(stdin);
gets(nume);
insert(&startPtr, nume);
printList(startPtr);
break;
case 2:
fflush(stdin);
printf("Search by name to delete from list:");
gets(nume);
if(!Empty(startPtr))
{
if(del(&startPtr, nume))
{
printf("%s was deleted!\n");
printList(startPtr);
}else printf("%s was not found!\n",nume);
}else
printf("List is empty!");
break;
case 3:
break;
default:
printf("No such option!\n\n");
instructions();
break;
}
printf("\n? ");
scanf("%d",&optiune);
}
printf("Execution stopped.\n" );
return EXIT_SUCCESS;
答案 0 :(得分:1)
问题中的代码有很多小问题,但是当这些问题被清除后,核心算法似乎可以正常工作。缩进在某些地方有点奇怪。从现在开始,我将忽略它。
不幸的是,批评可以很快开始:
struct listnode
{
char data[100];
listnode *nextPtr;
};
typedef struct listnode ListNode;
typedef ListNode *ListNodePtr;
这是一个C问题,但是如果代码曾经编译过,那是因为它是由C ++编译器编译的。 listnode *nextPtr;
在C中无效(但在C ++中有效)。在那一行,名称struct listnode
是已知的,但是没有listnode
前缀的类型struct
在任何标准标头中都没有定义(通常情况下,无论如何)。您需要struct listnode *nextPtr;
是有效的C。或者您需要将typedef struct listnode ListNode;
移动到结构定义之前,然后在结构中使用ListNode *nextPtr;
。您可能不应该定义或使用ListNodePtr
-有关原因的讨论,请参见Is it a good idea to typedef pointers?。您可以像这样清理代码。请注意,结构标签(例如ListNode
)在标签名称空间中(以及union
标签和enum
标签),但是typedef名称ListNode
在不同的“普通”标签中。标识符的名称空间-因此在此代码中ListNode
的使用之间没有冲突:
typedef struct ListNode ListNode;
struct ListNode
{
char data[100];
ListNode *nextPtr;
};
在下文中,“清理类型”是指使用ListNode
而不是ListNodePtr
或任何其他变体拼写。
清除类型后,insert()
中的代码就可以了;错误消息应打印到stderr
并进行拼写检查,并以换行符结尾。
del()
中的代码可能不在函数delete()
中,因为delete
是C ++编译器中的关键字,因此不能用作函数名。不要使用C ++编译器来编译C,否则会产生误导性的结果。
该函数的声明返回类型为const char *
,但返回的值不是指针。最好更改函数以返回int
或什至bool
来表明它是否成功删除了指定的名称。
在以下位置也有间隔错误:
previousPtr - > nextPtr = currentPtr->nextPtr;
点.
或箭头->
运算符之间不应有空格,-
和>
之间也不应有空格正式有一个箭头运算符。
但是,del()
中的核心算法似乎可以正常工作。可能还有改进的空间。
您引用的代码未定义(实际上是未声明)的函数,例如Empty()
,printList()
,instructions()
-创建MCVE(Minimal, Complete, Verifiable Example)时,您不应这样的遗漏。下面的代码为每种方法提供了简单的实现。
main()
中的代码显示了各种问题。一种是通过不编写有用的功能来完成特定工作的代码重复。我不知道您对instructions()
函数的计划是什么,但我保留了它,并将其简化为一个打印单个提示(末尾没有换行符)的单个printf()
。它本身是从get_option()
函数中使用的,该函数处理许多复杂的细节。
您应该 从不 使用gets()
功能;了解为什么it is far too dangerous to use gets()
— ever!。另外,将scanf()
与fgets()
之类的函数混合起来有点麻烦,因为scanf()
leaves the newline in the input buffer。我创建了函数get_option()
和get_string()
来处理问题,并处理无效(非数字)输入和意外的EOF等。它们还刷新标准输出,但不刷新标准输入。请参见Using fflush(stdin)
进行细微的讨论-可以说fflush(stdin)
不是可移植的,尽管它确实在Windows上已定义了行为,但是除了调用未定义的行为外,它在其他任何地方都做得很少。通常,避免使用它。如果必须使用它,请注意限制了代码的可移植性(通常没有必要这样做)。
有了“循环,输入和测试位于顶部”,main()
主体中的代码稍微简单一些。我在case 2:
代码中对测试进行了重新排序,以避免嵌套ifs。通常最好是在测试后做一些事情,而不是开始新的测试。
请注意,错误条件报告输入(读取)的值。这对用户来说很有价值-如果您将报告的值视为意外值,则可以更好地推断出出了什么问题。
将它们放在一起可以得到如下代码:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct ListNode ListNode;
struct ListNode
{
char data[100];
ListNode *nextPtr;
};
extern void insert(ListNode **strPtr, char value[]);
extern bool delete(ListNode **strPtr, char value[]);
void insert(ListNode **strPtr, char value[])
{
ListNode *previousPtr, *currentPtr, *newPtr;
newPtr = (ListNode *)malloc(sizeof(ListNode));
strcpy(newPtr->data, value);
newPtr->nextPtr = NULL;
previousPtr = NULL;
currentPtr = *strPtr;
if (newPtr != NULL)
{
while (currentPtr != NULL &&
strcmp(currentPtr->data, value) < 0)
{
previousPtr = currentPtr;
currentPtr = currentPtr->nextPtr;
}
if (previousPtr == NULL)
{
newPtr->nextPtr = *strPtr;
*strPtr = newPtr;
}
else
{
previousPtr->nextPtr = newPtr;
newPtr->nextPtr = currentPtr;
}
}
else
fprintf(stderr, "%s was not inserted. Insufficient memory!\n", value);
}
bool delete(ListNode **strPtr, char value[])
{
ListNode *previousPtr, *currentPtr, *tempPtr;
if (strcmp(value, (*strPtr)->data) == 0)
{
tempPtr = *strPtr;
*strPtr = (*strPtr)->nextPtr;
free(tempPtr);
return true;
}
else
{
previousPtr = *strPtr;
currentPtr = (*strPtr)->nextPtr;
while (currentPtr != NULL && strcmp(value, currentPtr->data) != 0)
{
previousPtr = currentPtr;
currentPtr = currentPtr->nextPtr;
}
if (currentPtr != NULL)
{
tempPtr = currentPtr;
previousPtr->nextPtr = currentPtr->nextPtr;
free(tempPtr);
return true;
}
}
return false;
}
static bool Empty(ListNode *ptr)
{
return(ptr == NULL);
}
static void get_string(size_t size, char buffer[size])
{
if (fgets(buffer, size, stdin) == 0)
{
fprintf(stderr, "Unexpected EOF on standard input\n");
exit(EXIT_FAILURE);
}
buffer[strcspn(buffer, "\n")] = '\0';
}
static void instructions(void)
{
printf("1 to add, 2 to delete, 3 to exit: ");
}
static int get_option(void)
{
int optiune;
instructions();
fflush(stdout);
if (scanf("%d", &optiune) != 1)
{
fprintf(stderr, "Failed to read option number\n");
exit(EXIT_FAILURE);
}
int c;
while ((c = getchar()) != EOF && c != '\n')
;
return optiune;
}
static void printList(ListNode *ptr)
{
for (int i = 0; ptr != NULL; i++)
{
printf("%d: %s\n", i, ptr->data);
ptr = ptr->nextPtr;
}
}
int main(void)
{
ListNode *startPtr;
startPtr = NULL;
int optiune;
char nume[100];
while ((optiune = get_option()) != 3)
{
switch (optiune)
{
case 1:
printf("Enter name: ");
fflush(stdout);
get_string(sizeof(nume), nume);
insert(&startPtr, nume);
printList(startPtr);
break;
case 2:
printf("Search by name to delete from list: ");
fflush(stdout);
get_string(sizeof(nume), nume);
if (Empty(startPtr))
printf("List is empty!\n");
else if (delete(&startPtr, nume))
{
printf("%s was deleted!\n", nume);
printList(startPtr);
}
else
printf("%s was not found!\n", nume);
break;
default:
fprintf(stderr, "No such option (%d)!\n\n", optiune);
break;
}
}
printf("Execution stopped.\n");
return EXIT_SUCCESS;
}
(我制作函数static
,除非有一个标头在其中声明它们,以及另一个将使用它们的源文件。这甚至可以帮助优化,因为编译器可以告诉一个static
函数被调用,并且我的代码是内联的。)
下面是上面代码的示例运行:
1 to add, 2 to delete, 3 to exit: 1
Enter name: Patricia
0: Patricia
1 to add, 2 to delete, 3 to exit: 1
Enter name: Persephone
0: Patricia
1: Persephone
1 to add, 2 to delete, 3 to exit: 1
Enter name: Piglet
0: Patricia
1: Persephone
2: Piglet
1 to add, 2 to delete, 3 to exit: 1
Enter name: Pooh
0: Patricia
1: Persephone
2: Piglet
3: Pooh
1 to add, 2 to delete, 3 to exit: 1
Enter name: Puss In Boots
0: Patricia
1: Persephone
2: Piglet
3: Pooh
4: Puss In Boots
1 to add, 2 to delete, 3 to exit: 1
Enter name: Pygmalion
0: Patricia
1: Persephone
2: Piglet
3: Pooh
4: Puss In Boots
5: Pygmalion
1 to add, 2 to delete, 3 to exit: 2
Search by name to delete from list: Pooh
Pooh was deleted!
0: Patricia
1: Persephone
2: Piglet
3: Puss In Boots
4: Pygmalion
1 to add, 2 to delete, 3 to exit: 2
Search by name to delete from list: Pygmalion
Pygmalion was deleted!
0: Patricia
1: Persephone
2: Piglet
3: Puss In Boots
1 to add, 2 to delete, 3 to exit: 2
Search by name to delete from list: Patricia
Patricia was deleted!
0: Persephone
1: Piglet
2: Puss In Boots
1 to add, 2 to delete, 3 to exit: 2
Search by name to delete from list: Piglet
Piglet was deleted!
0: Persephone
1: Puss In Boots
1 to add, 2 to delete, 3 to exit: 2
Search by name to delete from list: Puss In Boots
Puss In Boots was deleted!
0: Persephone
1 to add, 2 to delete, 3 to exit: 2
Search by name to delete from list: Quantum Gold
Quantum Gold was not found!
1 to add, 2 to delete, 3 to exit: 2
Search by name to delete from list: Persephone
Persephone was deleted!
1 to add, 2 to delete, 3 to exit: 3
Execution stopped.