c - 如何从用户接收字符串以接收空字符串并在c中打印它们

标签 c string

如何从用户接收字符串到c中的空字符串 接收字符串并放入数组中,然后打印它。

int main() {
    int i=0;
    char st[LEN];
    char ch;

    while(st[0]!='\0') {
        i=0;
        printf("Enter name of student:");

        while(ch!='\n') {
            ch=getchar();
            st[i]=ch;
            i++;
        }
    }
}

snapshot

最佳答案

您有多种选择可供考虑。首先,由于您正在阅读包含名称的lines-of-input,因此使用面向行的输入函数(例如fgets)非常有意义。那么您只需考虑两个因素来检查输入结束,(1) fgets 返回 NULL 指示 EOF 或 (2),您检查由 fgets 填充的缓冲区的第一个字符,以查看它是否是 '\n' 字符(表示已单独按下 Enter

接下来,您需要考虑将使用什么数据结构来保存名称数组,直到收集到所有输入。您可以使用 struct 数组,如其他答案中所示,或者您可以简单地使用 *pointer-to-pointer-to-char` (一个双指针 )根据需要分配指针,并为包含每个名称的已分配内存块分配地址。

该过程很简单。首先分配一些合理预期数量的指针来使用。读取名称,为每个名称分配存储空间,将名称复制到分配的内存,然后将内存地址分配给每个指针。当您达到当前分配的指针的限制时,只需realloc其他指针并继续。

一旦收集了所有名称,您只需输出名称(我也包括了指针索引),然后释放每个名称的内存,然后在打印并释放所有名称之后,释放指针,你就完成了。您可以执行类似于以下操作:

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

enum { MAXP = 32, MAXC = 256 };  /* constants */ 

void *xcalloc (size_t nmemb, size_t size); /* helper functions */
void *xrealloc (void *ptr, size_t psz, size_t *nelem, size_t inc);

int main (void) {

    size_t max = MAXP, n = 0;       /* initial ptrs and counter */
    char **a = xcalloc (max, sizeof *a);  /* mem for MAXP ptrs */ 

    for (;;) {                 /* loop until empty line or EOF */
        size_t len = 0;
        char buf[MAXC] = "";

        /* read into buf from stdin, check if empty */
        if (!fgets (buf, MAXC, stdin) || *buf == '\n')
            break;

        len = strlen (buf);     /* get length of buf */
        if (buf[len-1] == '\n') /* test for '\n' */
            buf[--len] = 0;     /* remove '\n' */

        a[n] = xcalloc (len + 1, 1);    /* mem to hold buf  */
        strcpy (a[n++], buf);           /* copy buf to a[n] */

        if (n + 1 == max) /* ptr limit reached, realloc ptr
                           * note: +1 insures a sentinel pointer
                           * with bits zeroed as the last pointer */
            a = xrealloc (a, sizeof *a, &max, MAXP);
    }

    for (size_t i = 0; i < n; i++) {    /* print and free mem */
        printf ("a[%3zd] : %s\n", i, a[i]);
        free (a[i]);   /* free memory allocated for each name */
    }
    free (a);  /* free pointers */

    return 0;
}

/* simple calloc with error-checking */
void *xcalloc (size_t nmemb, size_t size)
{
    void *memptr = calloc (nmemb, size);
    if (!memptr) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        exit (EXIT_FAILURE);
    }

    return memptr;
}

/* simple realloc with error-checking */
void *xrealloc (void *ptr, size_t psz, size_t *nelem, size_t inc)
{
    void *memptr = realloc ((char *)ptr, (*nelem + inc) * psz);
    if (!memptr) {
        fprintf (stderr, "realloc() error: virtual memory exhausted.\n");
        exit (EXIT_FAILURE);
    }   /* zero new memory (optional) */
    memset ((char *)memptr + *nelem * psz, 0, inc * psz);
    *nelem += inc; /* update number of elements allocated */

    return memptr;
}

上面的 256 个字符的静态缓冲区用于从 stdin 读取每个名称。如果由于任何原因这可能还不够,您始终可以通过添加长度检查并检查尾随 '\n' 来验证是否读取了完整的行。

示例使用/输出

$ ./bin/readprn <dat/namesfirst.txt
a[  0] : adam
a[  1] : allice
a[  2] : barny
a[  3] : beauregard
a[  4] : bell
a[  5] : benjamin
a[  6] : betty
a[  7] : bill
a[  8] : buck
a[  9] : buddy
a[ 10] : candice
a[ 11] : caset
a[ 12] : cathy
a[ 13] : charles
a[ 14] : chris
a[ 15] : chuck
a[ 16] : clark
a[ 17] : david
a[ 18] : don
a[ 19] : eli
a[ 20] : elizabeth
a[ 21] : emma
a[ 22] : eric
a[ 23] : ester
a[ 24] : frank

如果您手动键入每个名称,然后在最后一行单独按 Enter,则代码的行为相同。 (我只是碰巧有一个名称文件)

内存使用/错误检查

在您编写的动态分配内存的任何代码中,对于分配的任何内存块,您都有两个责任:(1) 始终保留指向起始地址的指针内存块,因此,(2) 当不再需要它时可以释放

您必须使用内存错误检查程序来确保您不会尝试在分配的内存块的范围之外进行写入,尝试读取未初始化的值或将条件跳转建立在未初始化的值上,最后,确认您释放了分配的所有内存。

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

$ valgrind ./bin/readprn <dat/namesfirst.txt
==28428== Memcheck, a memory error detector
==28428== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==28428== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==28428== Command: ./bin/readprn
==28428==
a[  0] : adam
<snip>
a[ 24] : frank
==28428==
==28428== HEAP SUMMARY:
==28428==     in use at exit: 0 bytes in 0 blocks
==28428==   total heap usage: 26 allocs, 26 frees, 413 bytes allocated
==28428==
==28428== All heap blocks were freed -- no leaks are possible
==28428==
==28428== For counts of detected and suppressed errors, rerun with: -v
==28428== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认您已释放分配的所有内存并且不存在内存错误。

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

关于c - 如何从用户接收字符串以接收空字符串并在c中打印它们,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44401662/

相关文章:

c - 数组条目在 C 中被覆盖

c# - 当单词出现的顺序或次数不重要时,两个字符串之间的最佳匹配?

c++ - 内存分配是如何完成的

c - 同样的C程序在Windows上无法运行,但在Linux上却可以完美运行

c - 如何引用二维数组中的单个字符?

java - 如何在Java中识别字符串数组中最长的字母单词? (任何不带符号或数字的子字符串)

ios - 如何使用 Swift 将 CKRecord 保存到具有多种类型信息的 CloudKit

c - 如何改进kmp算法以找到重叠结果

c - readdir 函数没有像我预期的那样工作

我们可以在创建进程后立即以编程方式将进程附加到 VS 吗?