从C中的txt文件中提取字符串

问题描述

我必须从一个 txt 文件和带有该字符串的行数中提取每个“Artykuł”。当我尝试编译我的程序时出现错误:“invalid initializer char str[]=line;”所以我不知道我应该如何将每行中的每个单词分别分配给一个字符表。

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1

int getWords(char *base,char target[10][20])
{
    int n=0,i,j=0;
    
    for(i=0;TRUE;i++)
    {
        if(base[i]!=' '){
            target[n][j++]=base[i];
        }
        else{
            target[n][j++]='\0';//insert NULL
            n++;
            j=0;
        }
        if(base[i]=='\0')
            break;
    }
    return n;
    
}
int main()
{
  FILE * fp;
    char * line = NULL;
    size_t len = 0;
    ssize_t read;

    fp = fopen("dyrekt.html","r");
    if (fp == NULL)
        exit(EXIT_FAILURE);
        while ((read = getline(&line,&len,fp)) != -1) {
    int n; //number of words
    int i; //loop counter 
    char str[]=line;
    char arr[10][20];
    
    n=getWords(str,arr);
    
    for(i=0;i<=n;i++)
        printf("%s\n",arr[i]);
    
    return 0;
}
fclose(fp);
    if (line)
        free(line);
    exit(EXIT_SUCCESS);
    }

解决方法

@Ramus05 的评论暗示了这一点,但我会在这里展开。我制作了一个简单的测试程序来测试您的代码元素。当我编译以下代码时:

#include <stdio.h>
int main()
{
    char* test = "this is a test string";
    char str[] = test;
    printf("%s\n",str);
}

我遇到了与您相同的错误。但是,此代码编译:

#include <stdio.h>
int main()
{
    char* test = "this is a test string";
    char* str = test;
    printf("%s\n",str);
}

当我运行它时,我得到以下输出:

this is a test string

这就是您解决问题的方法。

但我确定您想知道为什么会发生这种情况。好吧,复制的字符串变量(在我的情况下为 test,在您的情况下为 line)是内存中的一个指针。这个指针可以指向(理论上)任何长度的东西。但是,数组有些不同。它被分配为特定的长度。因此,C 不允许您将其初始化为可变长度的内容。

因此,例如,以下代码在 C 中有效:

char str[50] = "test string";

这是有效的,因为文字字符串 "test string" 是静态长度。

就您而言,您试图将 char[] 设置为可变长度,而 C 不允许这样做。更改为 char* 可以解决此问题,因为它是一个指针。或者,您可以静态分配一个数组并使用 strcpy 或更安全的 strncpy

,

您有大量问题需要更正。具体:

  1. 永远不要硬编码文件名或在代码中使用 MagicNumbers。您不必为了读取不同的文件名而重新编译您的程序。将文件名作为第一个参数传递给您的程序(这就是 argcargvint main (int argc,char **argv) 中的作用),或者提示用户并将文件名作为输入。而不是在你的代码(1020)中撒上幻数,#define 一个常量或使用一个全局 enum;
  2. 您不需要以 char str[] 开头,只需将 line 传递给 getWords()
  3. 您调用未定义行为读取超出数组末尾的内容,您的循环限制应为0 <= i < n,因此这意味着for (i = 0; i < n; i++) NOT i <= n;立>
  4. 不要在阅读循环结束时return 0;。这意味着您只在 1 次迭代完成后退出;
  5. getWords() 中,您必须保护数组边界。如果一行中有超过 10 个单词,或者单词中有超过 19 个字符怎么办?如果您为数组边界定义了常量,则只需将比较添加到循环条件和 if() 条件;
  6. 在循环 TRUE 时不要将 base 用于连续循环,正确的循环限制是数组中的行数。如果您有 #define ROWS 10,那么您的 i 循环是 for (i = 0; n < ROWS; i++)。您必须对 j 计数执行相同操作。如果你 #define COLS 20,你会做 if (j == COLS - 1 || isspace (base[i])) 来保护你的列限制,同时还捕获 ' ' 作为词尾;和
  7. 你必须知道你是在一个字读字符,还是字读空格之间。否则,如果您的行在单词之间有前导、尾随或多个包含空格,则您的 arr 将为遇到的每个 '\0' 保存一个 ' '(空字符串)。您可以简单地使用 int inword = 0; 作为标志,并在读取字符时将其设置为 1 (true),或者在遇到空格时将其设置为 0。然后您只需向数组 if (inword) 添加一个单词。

现在要解决这个问题,首先要声明数组的常量:

#define ROWS 10         /* if you need a constant,#define one (or more) */
#define COLS 20

将要读取的文件名作为程序的第一个参数(如果没有提供参数,则默认从 stdin 读取),例如

int main (int argc,char **argv) {
    
    ...
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1],"r") : stdin;

    // fp = fopen ("dyrekt.html","r");     /* NEVER hardcode filenames */
    if (fp == NULL) {
        perror ("fopen-file");
        exit (EXIT_FAILURE);
    }

line 传递给 getwords(),然后修复 main() 中的循环限制以显示单词并删除不需要的 return 0;

        n = getWords (line,arr);           /* pass line,str not needed */

        for (i = 0; i < n; i++)             /* i < n,not i <= n */
            printf ("%s\n",arr[i]);

        // return 0;    /* what? you exit at end of iteration */

最后,getwords() 的所有更改,包括保护数组边界的检查都可以按如下方式完成:

int getWords (char *base,char (*target)[COLS])
{
    int n = 0,i,j = 0,inword = 0;        /* inword is flag for in/out of word */

    for (i = 0; n < ROWS; i++) {                    /* protect array bounds */
        if (j == COLS - 1 || isspace (base[i])) {   /* both ROWS and COLS  */
            if (inword) {                           /* check if inword before adding */
                target[n][j++] = '\0';              //insert NULL
                n++;
                inword = j = 0;                     /* reset inword as well as j */
            }
        }
        else {
            target[n][j++] = base[i];
            inword = 1;                             /* set inword true */
        }
        if (!base[i])
            break;
    }
    
    return n;
}

注意:您应该在 j == COLS - 1 的情况下添加额外的错误处理来处理不适合的额外字符。您可以使用 {{1 }})

总而言之,你会:

for (int c = getchar(); !isspace(c) && c != EOF; c = getchar()) {}

注意:初始化一个二维数组是个好主意,用于保存字符串全为零)

示例输入文件

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>      /* use issspace() to check whitespace */

#define ROWS 10         /* if you need a constant,#define one (or more) */
#define COLS 20

int getWords (char *base,inword = 0;        /* inword is flag for in/out of word */

    for (i = 0; n < ROWS; i++) {                    /* protect array bounds */
        if (j == COLS - 1 || isspace (base[i])) {   /* both ROWS and COLS  */
            if (inword) {                           /* check if inword before adding */
                target[n][j++] = '\0';              //insert NULL
                n++;
                inword = j = 0;                     /* reset inword as well as j */
            }
        }
        else {
            target[n][j++] = base[i];
            inword = 1;                             /* set inword true */
        }
        if (!base[i])
            break;
    }
    
    return n;
}

int main (int argc,char **argv) {
    
    char *line = NULL;
    size_t len = 0;
    ssize_t read;
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1],"r");     /* NEVER hardcode filenames */
    if (fp == NULL) {
        perror ("fopen-file");
        exit (EXIT_FAILURE);
    }
    
    while ((read = getline (&line,&len,fp)) != -1) {
        int n,//number of words
            i;                              //loop counter 
        char arr[ROWS][COLS] = enter image description here;       /* initialize arrays */

        n = getWords (line,arr[i]);

        // return 0;    /* what? you exit at end of iteration */
    }
    fclose (fp);
    
    free (line);        /* no neef for if,calling free (NULL) doesn't hurt */
    
    exit (EXIT_SUCCESS);
}

示例使用/输出

将要读取的文件作为第一个参数传递:

$ cat dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.

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