有没有办法读取字符并将它们存储在链接列表中,直到按Enter为止?

问题描述 投票:0回答:1

我一直在尝试将一个字符串输入链接列表,直到按下Enter键为止。我想将每个字符放入单独的节点。

这是我的代码:

charNode* readString(){
char c;
charNode *head, *cur, *last;
head = NULL;
while(1){
    scanf("%c", &c);
    if(c == '\n'){
        break;
    }else{
        if(head ==NULL){
            head = malloc(sizeof(struct charNode));
            head->c = c;
            last = head;
            last->next = NULL;
        }else{
            cur = malloc(sizeof(struct charNode));
            cur->c = c;
            cur->next = NULL;
            last->next = cur;   
        }
    }

}
return head;

}

当我在执行过程中按Enter键时,scanf函数似乎根本无法检测到它。

c scanf
1个回答
1
投票

关于您的代码,有几点注意事项。首先,如注释中所示,您的读取循环应基于读取功能本身的返回。如果要使用scanf,则可以执行以下操作:

while (scanf("%c", &c) == 1 && c != '\n')

尽管从stdin中读取单个字符,但我建议例如单独执行此功能的函数>

while ((c = getchar()) != '\n' && c != EOF)

下一步,在readString()函数中,您无法将last指针更新为由@JohnnyMopp指示的最后添加的节点。您需要将last = cur;添加为else语句下的最后一个表达式。

此外,通过在head函数中声明tailreadString()并仅返回head,您会丢失tail指针。最好声明一个简单的wrapper

结构,该结构包含headtail指针(以及您喜欢的任何其他列表统计信息),然后返回一个指向该包装器结构的指针,以保留readString()中的所有列表信息]。例如:
/** linked list node */
typedef struct node_t {
    char data;
    struct node_t *next;
} node_t;

/** linked list */
typedef struct {
    node_t *head, *tail;
} list_t;

然后通过分配并返回指向list_t类型的指针,可以保留headtail节点信息。编写readString()函数时,将FILE*指针作为参数传递可能会有所帮助,以便您可以从任何喜欢的打开文件流中读取。如果要从stdin中读取,只需将stdin作为开放流传递即可。它为您的字符串源增加了很大的灵活性,同时几乎没有增加函数的复杂性。您的readString()函数可能是:

list_t *readstr (FILE *fp)
{
    if (!fp)                            /* validate stream not NULL */
        return NULL;

    int c;                              /* int to read (must be int for EOF) */
    list_t *l = malloc (sizeof *l);     /* allocate for list */

    if (!l) {                           /* validate list allocation */
        perror ("malloc-l");
        return NULL;
    }
    l->head = l->tail = NULL;           /* initialize list head/tail ptrs NULL */

    if (fp == stdin)                    /* if reading from stdin */
        fputs ("enter string: ", stdout);   /* prompt for string */

    while ((c = fgetc(fp)) != '\n' && c != EOF)     /* read each character */
        if (!add (l, c)) {              /* add node, validate */
            del_list (l);               /* on add failure, free all memory */
            l = NULL;                   /* set pointer NULL */
            break;
        }

    return l;   /* return pointer to list on success, NULL otherwise */
}

以这种方式进行处理使列表存储器的实际填充,使用和释放变得非常简单。简短的main()将减少为:

int main (void) {

    list_t *l = NULL;                       /* pointer to list */

    if ((l = readstr (stdin))) {            /* read string into list/validate */
        prn (l);                            /* print all nodes */
        del_list (l);                       /* free all allocated memory */
    }
}

char读取的stdin的链表的简短实现如下:

#include <stdio.h>
#include <stdlib.h>

/** linked list node */
typedef struct node_t {
    char data;
    struct node_t *next;
} node_t;

/** linked list */
typedef struct {
    node_t *head, *tail;
} list_t;

/** add node at end of list, update tail to end */
node_t *add (list_t *l, char c)
{
    node_t *node = malloc (sizeof *node);   /* allocate node */
    if (!node) {                            /* validate allocation */
        perror ("malloc-node");
        return NULL;
    }
    node->data = c;                         /* initialize members values */
    node->next = NULL;

    if (!l->head)                   /* if 1st node, node is head/tail */
        l->head = l->tail = node;
    else {                          /* otherwise */
        l->tail->next = node;       /* add at end, update tail pointer */
        l->tail = node;
    }

    return node;    /* return new node */
}

/** print all nodes in list */
void prn (list_t *l)
{
    if (!l->head) {
        puts ("list-empty");
        return;
    }
    for (node_t *n = l->head; n; n = n->next)
        printf (" %c", n->data);
    putchar ('\n');
}

/** delete all nodes in list */
void del_nodes (list_t *l)
{
    node_t *n = l->head;
    while (n) {
        node_t *victim = n;
        n = n->next;
        free (victim);
    }
}

/** delete list and all nodes in list */
void del_list (list_t *l)
{
    del_nodes (l);
    free (l);
}

list_t *readstr (FILE *fp)
{
    if (!fp)                            /* validate stream not NULL */
        return NULL;

    int c;                              /* int to read (must be int for EOF) */
    list_t *l = malloc (sizeof *l);     /* allocate for list */

    if (!l) {                           /* validate list allocation */
        perror ("malloc-l");
        return NULL;
    }
    l->head = l->tail = NULL;           /* initialize list head/tail ptrs NULL */

    if (fp == stdin)                    /* if reading from stdin */
        fputs ("enter string: ", stdout);   /* prompt for string */

    while ((c = fgetc(fp)) != '\n' && c != EOF)     /* read each character */
        if (!add (l, c)) {              /* add node, validate */
            del_list (l);               /* on add failure, free all memory */
            l = NULL;                   /* set pointer NULL */
            break;
        }

    return l;   /* return pointer to list on success, NULL otherwise */
}

int main (void) {

    list_t *l = NULL;                       /* pointer to list */

    if ((l = readstr (stdin))) {            /* read string into list/validate */
        prn (l);                            /* print all nodes */
        del_list (l);                       /* free all allocated memory */
    }
}

(<< [note:

通过使用list_t包装器,您可以声明并填充任意数量的列表,并且将为每个列表保留headtail指针)此外,单独的del_nodes()del_list()函数使您可以将list_t结构与

自动存储持续时间

使用(例如list_t l = { NULL, NULL };),然后仅使用free()个已分配的节点而无需调用free() ]上的列表。

示例使用/输出

$ ./bin/llchargetchar enter string: my dog has fleas m y d o g h a s f l e a s

内存使用/错误检查

在您编写的任何可动态分配内存的代码中,对于任何已分配的内存块,您都有2个

职责

:(1)始终保留指向起始地址的指针,因此,( 2)不再需要它时,可以将其freed必须使用内存错误检查程序,以确保您不尝试访问内存或不要在分配的块的边界之外/之外写,尝试读取或基于未初始化的值进行条件跳转,最后,确认您释放了已分配的所有内存。

对于Linux valgrind是正常选择。每个平台都有类似的内存检查器。它们都很容易使用,只需通过它运行程序即可。

$ valgrind ./bin/llchargetchar ==25923== Memcheck, a memory error detector ==25923== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==25923== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==25923== Command: ./bin/llchargetchar ==25923== enter string: my dog has fleas m y d o g h a s f l e a s ==25923== ==25923== HEAP SUMMARY: ==25923== in use at exit: 0 bytes in 0 blocks ==25923== total heap usage: 19 allocs, 19 frees, 2,320 bytes allocated ==25923== ==25923== All heap blocks were freed -- no leaks are possible ==25923== ==25923== For counts of detected and suppressed errors, rerun with: -v ==25923== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认已释放已分配的所有内存,并且没有内存错误。

仔细检查,如果还有其他问题,请告诉我。

© www.soinside.com 2019 - 2024. All rights reserved.