繁体   English   中英

如何使用 C 从键盘读取字符串(包括所有换行符)?

[英]How to read string from keyboard (including all newlines) using C?

下面将使用lorem.txt作为测试文件:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

我有以下代码用于计算文件中的行数、单词和字符(试图模仿 Linux 中的wc ):

#include <stdio.h>

int main(){
    char data[500032];  // assigns 500KB of space for input string
    if (fgets(data, sizeof data, stdin)) {
        char *ptr = &data[0];  // initializes pointer at first character
        int count = 0;  // total character count
        int d1_count = 0;  // newline count
        int d23_count = 0;  // ' ' and '\t' count

        while (*ptr){
            char d1 = '\n';
            char d2 = ' ';
            char d3 = '\t';
            count++;  // counts character
            if (*ptr == d1){
                d1_count++; // counts newline
            }
            if (*ptr == d2 || *ptr == d3) {
                d23_count++;  // counts spaces or tabs
            }
            ptr++;  // increments pointer
        }
        printf("%d %d %d\n", d1_count, d23_count+1, count-1);
    }
}

在我的 Linux 终端中,我使用gcc -o wordc wordc.c编译然后./wordc < lorem.txt

但是,我得到1 69 445 (1 行,69 个单词和 445 个字符)。 这只是第一段的行数、单词数和字符数。 我期待 7 行、207 个单词和 1342 个字符。

我假设正在发生的事情是 C 一旦找到换行符就会停止读取文件。 我如何让它停止这样做?

顺便说一句,我觉得为字符串分配 500KB 的空间有点笨拙和浪费。 有什么好的方法可以只分配我需要的空间吗?

任何帮助,将不胜感激

换行

if (fgets(data, sizeof data, stdin)) {

while (fgets(data, sizeof data, stdin)) {

这样您就可以在每次循环迭代中读取一行。

您还必须移动线条

int count = 0;  // total character count
int d1_count = 0;  // newline count
int d23_count = 0;  // ' ' and '\t' count

在循环之外,因为您想在循环迭代之间记住这些值。

您还需要移动线路

printf("%d %d %d\n", d1_count, d23_count+1, count-1);

如果您只想打印该行一次,而不是每次循环迭代一次,则在循环之外。

我觉得为一个字符串分配 500KB 的空间有点笨拙和浪费。 有什么好的方法可以只分配我需要的空间吗?

缓冲区必须足够大以存储单行。 它不必一次存储整个文件。 因此,使用明显更小的缓冲区可能就足够了。

尽管可以使用动态分配的缓冲区(使用malloc )并根据需要调整缓冲区的大小(使用realloc ),但在这种情况下,可能没有必要。

由于您在问题中声明您正在使用 Linux,因此另一种方法是使用 POSIX-specfic function getline ,它为您处理大部分 ZCD69B4957F06CD818D7BF3D61980E2。

我已经重写了您的程序以使用getline

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

int main() {
    char *data = NULL;
    size_t data_capacity = 0;
    int count = 0;  // total character count
    int d1_count = 0;  // newline count
    int d23_count = 0;  // ' ' and '\t' count

    while ( getline( &data, &data_capacity, stdin ) >= 0 ) {
        char *ptr = &data[0];  // initializes pointer at first character

        while (*ptr){
            char d1 = '\n';
            char d2 = ' ';
            char d3 = '\t';
            count++;  // counts character
            if (*ptr == d1){
                d1_count++; // counts newline
            }
            if (*ptr == d2 || *ptr == d3) {
                d23_count++;  // counts spaces or tabs
            }
            ptr++;  // increments pointer
        }
    }

    free( data );

    printf("%d %d %d\n", d1_count, d23_count+1, count-1);
}

使用问题中指定的输入,此程序具有以下 output:

5 205 1339

这个 output 不太正确,因为您计算的是程序中的空格数,而不是字数。 您似乎试图通过在打印该值时将空格数加1来弥补这一点。 然而,这还不够。 确切的解决方案取决于几个因素,例如您希望如何处理由连字符和换行符分隔的单词,即您是否要将此类单词计为一个单词或两个单词。 但是,由于这不是您在问题中陈述的问题,因此我不会讨论该问题。

当有这么多变量相互影响时,很难说会发生什么。

当我“选择”并将您的示例数据复制/粘贴到方便的形式时,在第 1 行和第 3 行的末尾(就在 LF 之前)似乎有一个不可见的字符。这可能是字符数之间的微小差异你得到什么,你期望什么。 (将标准输入重定向为来自stdin文件可能具有不可见的 CR/LF 对。不适用于此 OP,但对于非 Unix 读者来说值得注意。)

因此,计算空白字符并摆弄它们的值并不是确定什么会被识别为“单词”的方法(可能带有句号)

这是一个更值得信赖的版本。 从文件中读取并不麻烦。 可以使用“外部数据”将索引替换为c = fgetc( stdin ); (和ungetc()在“预读”中摸索单词的结尾。)

#include <stdio.h>
#include <ctype.h>

char *in =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. "
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. "
"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
"\r\n" // <== ???
"\n"
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. "
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. "
"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
"\r\n" // <== ???
"\n"
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. "
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. "
"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
"\n";

int main() {
    int lcnt = 0, wcnt = 0, ccnt = 0;

    for( int i = 0; in[i]; i++ ) {
        ccnt++;
        if( in[i] == '\n' )
            lcnt++;
        if( !isspace( in[i] ) ) {
            wcnt++;
            while( in[i+1] && !isspace( in[i+1] ) ) ccnt++, i++;
        }
    }

    printf( "%d lines, %d words, %d chars\n", lcnt, wcnt, ccnt );
    return 0;
}

这是 output

5 lines, 207 words, 1342 chars

// 207 / 3 = 69 words per populated line.

//   445x? + 1xCR + 1xLF
// +   1xLF
// + 445x? + 1xCR + 1xLF
// +   1xLF
// + 445x? + 1xLF
// = 1342

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM