- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我的程序应该从文本文件中读取每个单词,然后将其添加到链接列表中,但在我输入用户输入后它崩溃了。我不知道为什么。我尝试了很多不同的功能和方法,但它仍然崩溃。我搞不清楚了。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char *data;
struct node *next;
};
void insertNode(struct node**, char *);
void printList(struct node*);
int main()
{
struct node *head = NULL;
FILE *fptr;
char file_name[20];
char str[1000];
int numOfChar;
printf("Enter the name of the file: ");
scanf("%s",file_name);
printf("Enter the number of characters per line: ");
scanf("%d",&numOfChar);
fptr=fopen(file_name,"r");
while(fscanf(fptr, "%s ", str) != EOF)
{
insertNode(&head, str);
}
fclose(fptr);
printList(head);
return 0;
}
void insertNode(struct node** nodeHead, char *data)
{
struct node* new_node = malloc(sizeof *new_node);
new_node->data = strdup(data);
new_node->next = NULL;
while (*nodeHead)
nodeHead = &(*nodeHead)->next;
*nodeHead = new_node;
}
void printList(struct node* node)
{
while(node != NULL)
{
printf(" %s ", node->data);
node = node->next;
}
}
最佳答案
无论您使用哪种语言进行编码,如果您没有验证您的输入并且函数调用返回,您就无法确信您的代码正在正确执行任何操作,更重要的是,您将不知道在什么时候你的代码开始失败。这是根本性的。我知道您正在学习,但要从验证所有输入和所有函数调用返回的好习惯开始。您作为程序员的生活将会变得更加轻松。
实现简单的验证将告诉您代码在哪里失败以及在什么时候开始失败。例如,每次您接受输入时,请验证您确实得到了您所期望的内容。随着scanf
函数系列,这意味着至少要验证已成功进行的转换次数。如果您不清楚函数返回什么,或者如何衡量成功/失败,请查看该函数的手册页。该声明准确地告诉您期望返回的类型,然后手册页的正文准确地告诉您成功/失败的含义。
printf ("Enter the name of the file: ");
if (scanf("%[^\n]%*c", file_name) != 1) { /* validate conversion */
fprintf (stderr, "error: scanf filename conversion failed.\n");
return 1;
}
printf ("Enter the number of characters per line: ");
if (scanf ("%d%*c",&numOfChar) != 1) { /* validate conversion */
fprintf (stderr, "error: scanf numOfChar conversion failed.\n");
return 1;
}
if (!(fptr = fopen (file_name,"r"))) { /* validate file open */
fprintf (stderr, "error: file open failed for '%s'.\n", file_name);
return 1;
}
(侧节点:C 的样式规范,避免使用 caMelCase 变量名称,首选全部小写。参见例如 NASA - C Style Guide, 1994 )
在您编写的动态分配内存的任何代码中,对于分配的任何内存块,您都有 2 个责任:(1) 始终保留指向内存块起始地址的指针,因此,< strong>(2)当不再需要时可以将其释放。
您必须使用内存错误检查程序来确保您正确使用分配的内存,并且在不再需要时将其全部释放。有许多微妙的方法可以滥用新的内存块。对于 Linux valgrind
是正常的选择。 (使用起来非常简单,只需valgrind ./yourprogram
)
要释放列表,您需要释放 strdup
分配的所有内存。以及直接使用 malloc
分配的内存。对于列表,您需要创建第二个指针来保存要释放的 block 的地址,以便您可以分配 node = node->next
在删除节点之前。一个简短的例子是:
void freelist (struct node *node)
{
while (node) {
struct node *victim = node;
node = node->next;
free (victim->data);
free (victim);
}
}
将所有部分放在一起,进行最少的验证并正确使用 free
可能看起来像:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAXF = 20, MAXC = 1000 };
struct node {
char *data;
struct node *next;
};
void insertnode (struct node**, char *);
void printlist (struct node*);
void freelist (struct node *node);
int main (void) {
struct node *head = NULL;
FILE *fptr;
char file_name[MAXF];
char str[MAXC];
int numOfChar = 0; /* note: does nothing currently */
printf ("Enter the name of the file: ");
if (scanf("%[^\n]%*c", file_name) != 1) { /* validate conversion */
fprintf (stderr, "error: scanf filename conversion failed.\n");
return 1;
}
printf ("Enter the number of characters per line: ");
if (scanf ("%d%*c",&numOfChar) != 1) { /* validate conversion */
fprintf (stderr, "error: scanf numOfChar conversion failed.\n");
return 1;
}
if (!(fptr = fopen (file_name,"r"))) { /* validate file open */
fprintf (stderr, "error: file open failed for '%s'.\n", file_name);
return 1;
}
while (fscanf (fptr, "%s ", str) != EOF)
insertnode (&head, str);
fclose (fptr);
printlist (head);
freelist (head);
return 0;
}
void insertnode (struct node **nodeHead, char *data)
{
struct node *new_node = malloc (sizeof *new_node);
if (!new_node) {
fprintf (stderr, "error: virtual memory exhausted - new_node.\n");
exit (EXIT_FAILURE);
}
new_node->data = strdup(data);
new_node->next = NULL;
while (*nodeHead)
nodeHead = &(*nodeHead)->next;
*nodeHead = new_node;
}
void printlist (struct node *node)
{
while (node) {
printf(" %s ", node->data);
node = node->next;
}
putchar ('\n');
}
void freelist (struct node *node)
{
while (node) {
struct node *victim = node;
node = node->next;
free (victim->data);
free (victim);
}
}
仔细检查一下,如果您还有其他问题,请告诉我。
insertnode
的第二种方法
由于您遇到 insertnode
的问题,还有另一种方法可以迭代当前节点(实际上还有更多)。尝试以下操作:
void insertnode (struct node **nodeHead, char *data)
{
if (!data || !*data) {
fprintf (stderr, "error: invalid 'data' passed to insertnode '%s'.\n",
data);
exit (EXIT_FAILURE);
}
struct node *new_node = malloc (sizeof *new_node);
if (!new_node) {
fprintf (stderr, "error: virtual memory exhausted - new_node.\n");
exit (EXIT_FAILURE);
}
new_node->data = strdup(data);
new_node->next = NULL;
if (!*nodeHead) {
*nodeHead = new_node;
}
else {
while ((*nodeHead)->next)
nodeHead = &((*nodeHead)->next);
(*nodeHead)->next = new_node;
}
}
使用单独的指针进行迭代
void insertnode (struct node **nodeHead, char *data)
{
if (!data || !*data) {
fprintf (stderr, "error: invalid 'data' passed to insertnode '%s'.\n",
data);
exit (EXIT_FAILURE);
}
struct node *new_node = malloc (sizeof *new_node);
if (!new_node) {
fprintf (stderr, "error: virtual memory exhausted - new_node.\n");
exit (EXIT_FAILURE);
}
new_node->data = strdup(data);
new_node->next = NULL;
if (!*nodeHead)
*nodeHead = new_node;
else {
struct node *iter = *nodeHead;
for (; iter->next; iter = iter->next) {}
iter->next = new_node;
}
}
<小时/>
回答您的第二个问题与打印
虽然我喜欢fgets
接近你的列表,比 scanf
好得多,我比现在更喜欢你的第一个列表布局。由于评论中给出的原因,您在这里的解析实现是一场灾难。 strtok
(或 strsep
)是将字符串分解为单词的正确解析函数(或者您可以使用指针来完成它 - 但它需要的比您拥有的要多得多。查看 strtok
的手册页。这是一个使用的示例它进行分词:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct list {
char *string;
struct list *next;
} LIST;
void freelist (struct list *node);
int main (void) {
FILE *fp;
char line[128];
char file_name[20];
LIST *current, *head;
char *p;
char *delim = " \t\r\n";
head = current = NULL;
printf ("Enter the name of the file: ");
scanf("%s",file_name);
fp = fopen(file_name, "r");
while(fgets(line, sizeof(line), fp))
{
for (p = strtok (line, delim); p; p = strtok (NULL, delim))
{
LIST *node = malloc (sizeof(LIST));
if (!(node->string = strdup (p))) {
fprintf (stderr, "error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
node->next = NULL;
if (!head)
current = head = node;
else {
current->next = node;
current = current->next;
}
}
}
fclose(fp);
for (current = head; current; current = current->next) {
printf(" %s", current->string);
}
putchar ('\n');
freelist (head);
return 0;
}
void freelist (struct list *node)
{
while (node) {
struct list *victim = node;
node = node->next;
free (victim->string);
free (victim);
}
}
尝试一下——希望没有问题——我在键盘上睡着了。
关于c - 尝试从文本文件中读取单词并添加到链接列表,程序崩溃,我不知道为什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36108661/
我遇到以下问题。我想读取一个包含数百万行和数百列的大型 csv。我想向下转换列的数据类型。我的方法是读取 csv,然后使用 pd.to_numeric() 对其进行向下转换。我不知道列数及其类型。在读
目前,我从 SQL server (2008) 数据库获取数据。 cyurrent的方法是使用DataTable,然后将其传递并使用。 if (parameters != null)
我有以下问题。我有一个巨大的 csv 文件,想用多处理加载它。对于一个包含 500000 行和 130 列不同数据类型的示例文件,Pandas 需要 19 秒。我试过 dask 因为我想多处理阅读。但
是否有关于用于序列化各种 MFC 数据结构的二进制格式的明确文档?我已经能够在十六进制编辑器中查看我自己的一些类,并使用 Java 的 ByteBuffer 类读取它们(使用自动字节顺序转换等)。 但
我正在使用 Selenium 进行测试,我们用 HTML 文件编写测试用例,并用它们制作测试套件,我们的要求是编写足够健壮的测试用例,以根据测试环境改变自身。 为此,我不希望在 HTML 脚本本身中包
我需要一个 JavaScript 代码来读取存储为 .txt 文件的字典(或者也可以保存为任何其他类型的文件。它也可以在线获得)并将其内容存储在一个变量中。我不能找到一种让 JavaScript 像
我正在尝试遍历包含 SSH 登录和其他日志的日志文本文件。 程序正在返回 SSH 登录的总数。 我的解决方案确实有效,但似乎有点慢(在 200mo 文件上大约需要 3.5 秒)。我想知道是否有任何方法
我正在将大量数据从一个电子表格复制到工作簿中的其他 160 个电子表格。目前,Excel (2013) 遇到错误,因为它没有足够的资源来完成操作。 我的目标是将工作表 4 中 V13:XI1150 范
我正在尝试读取一个有 1147 行的文本文件。下面的代码仅读取第 1050-1147 行。我的目标是读取整个文件并提取位于不同行的特定值以在脚本中使用。一个示例是包含“BlockList: 2”的行中
我正在为游戏编写解释器。用户将其移动输入解释器,程序执行该移动。 现在我想为每个决定实现一个时间限制。玩家不应该能够思考超过 30 秒来写一个移动并按下回车。 call_with_time_limit
以this file例如,我正在尝试读取 data.frame 中的数据。来自 the doc (pdf 文件,表 1),它遵循一些 fortran 约定。我尝试了以下但收效甚微: dir 0' 将
我正在使用 R 阅读 Outlook 附件。我的引用在这里:Download attachment from an outlook email using R 这是我的电子邮件的截图: 这每天都会发送
我不会从表格中读取行来将主题放在列表中 php脚本 $url_obj='http://'.$host.':8069/xmlrpc/object'; $sock=new xmlrpc_client($u
我有一个这样的 csv 文件: id,name,value 1,peter,5 2,peter\,paul,3 我如何读取此文件并告诉 R "\," 不表示新列,仅表示 ","。 我必须添加该文件
我正在尝试读取 ~/Library/Preferences/com.apple.mail.plist (在 Snow Leopard 上)以获取电子邮件地址和其他信息以进入“关于”对话框。我使用以下代
This question already has answers here: How do I use floating-point division in bash? (19个回答) 5个月前关闭
本练习的目标是读取输入文件并将其存储到表中,然后验证输入中的某些字段并输出任何错误记录。我需要读取并存储每个策略组,以便表中一次仅存储 5 条记录,而不是整个文件。 所以我需要读取一个包含 5 条记录
据我了解,LWT 插入始终以 SERIAL 一致性级别完成。如果为 true,这是否意味着读取作为 LWT 插入的行可以安全地以 ANY 的一致性级别读取? 换句话说,我假设 LWT 插入是完全一致的
我看到很多很多通过java脚本读取cookie的函数,但我只想在变量中使用它一次,我是JS新手。 这是我的代码 var TheNumber = (Math.random() + '') * 10000
我正在使用 asp.net 和 C#。我在服务器上部署了一个应用程序[已发布],现在我想查看该网站的代码,据我所知,我可以阅读程序集来查看代码。 请告诉我如何实现它。 提前致谢。 最佳答案 您可以使用
我是一名优秀的程序员,十分优秀!