- 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/
我有一个简单的 pyparsing 构造,用于提取日志消息的部分内容。看起来像这样 log_line = 时间戳 + task_info + Suppress(LineEnd()) 此结构可以很好地解
我想定义一个函数 scaryDict(),它接受一个参数(textfile)并返回 textfile 中的单词按字母顺序排列,基本上生成字典但不打印任何一个或两个字母的单词。 这是我目前所拥有的……不
我正在尝试弄清楚如何包含对外部数据文件(文本形式)的引用,我希望通过 Web Start (JNLP) 与我的应用程序一起分发该文件。筛选 JNLP 结构的文档,我发现您可以包含对 JAR、nativ
我尝试将 Java 程序从 Eclipse 导出到 .jar 文件,但遇到了问题。它运行良好,但由于某种原因它没有找到它应该从中获取数据的文本文件。如果有人能帮忙解决这个问题,我将非常感激。 最佳答案
在过去的 20 个小时里,我试图解决以下问题,所以在开始考虑跳出窗外之前我想,我最好在这里寻求帮助: I have a text file with following content: ID 1 T
今天我试图删除一个简单文本文件中的重复行,例如: input (list.txt): hello hello try output (list.txt): try 我尝试使用 Notepad++ 删除
我将一个文本文件添加到我的项目中,如下路径所示: Myproject/WebPages/stopwords.txt 图片: http://s7.postimg.org/w65vc3lx7/Untitl
所以我在我的程序上工作,现在我无法找到解决方案。我需要在 fext 文件中替换更多的符号,目前程序只将“TIT”替换为代码“*245$a”,如果我想用同样的方式替换其他字母,程序不会改变。有人知道如何
这是一个非常简单的问题,但无论我看哪里,我都会得到不同的答案(这是因为它在 c++0x 中已经改变还是将要改变?): 在 C++ 中,我如何从一个文本文件中读取两个数字并将它们输出到另一个文本文件中?
我有一个 C++ 项目应该添加 到每一行的开头和到每一行的末尾。这适用于普通英文文本,但我有一个中文文本文件,我想这样做,但它不起作用。我通常使用 .txt 文件,但为此我必须使用 .rtf 来保存中
所以我的驱动看起来像这样: #include "problem2.h" #include "problem1.h" #include "problem3.h" #include #include
我有一个包含字符串标识符的 ascii 数字文本文件(>50k 行),可以将其视为数据 vector 的集合。根据用户输入,应用程序在运行时只需要这些数据 vector 之一。 据我所知,我有 3 个
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求提供代码的问题必须表现出对所解决问题的最低限度理解。包括尝试过的解决方案、为什么它们不起作用,以及预
这个问题在这里已经有了答案: 关闭 12 年前。 Possible Duplicate: Any decent text diff/merge engine for .NET ? 我有两个文本文件,
我正在尝试将对话选择器中的唤醒时间和 sleep 时间记录到这样的文本文件中,但是对方法 commitToFile2 的调用不会 append 文本文件“savedData.txt”。 我知道这段代码
我开发了一个 android webview 并尝试在单击 webview 中的链接时下载生成的数据:文本文件。 webView.setDownloadListener(new Downloa
我在一个文本文件中有 250 张图像/天 4000*3000 像素。 file '/home/user/camdata/nonseqdata.jpg' file '/home/user/camdata
我曾多次尝试将此配置文件转换为多维数组,这意味着我必须读取 config.txt 文件,然后必须将其转换为多维数组。我需要帮助或一些建议。 配置文件: id=www session.timeout=1
我正在尝试使用 sublime text 3 打开文件,我想用光标在具体行号处打开它。 我一直在查subl --help但我找不到混凝土线的选择。因此我只是使用:subl filename 有没有办法
我想在我的应用程序中快速显示一个大文本文件的内容,而不是将整个文件加载到内存中。 其他人是怎么做的? Total Commander是一个很棒的工具,它有一个很棒的内部查看器可以做到这一点。无论文件有
我是一名优秀的程序员,十分优秀!