【问题标题】:Using strcat to concatenate lines from a file使用 strcat 连接文件中的行
【发布时间】:2016-02-16 20:46:45
【问题描述】:

我正在尝试读取一个文件和下一行,以查看它是否以空格开头,例如:

First line
 second line 
Third line
 fourth line

当我读入文件时,我想检查下一行是否有空格,如果有,我想对这两行(在本例中为第一行和第二行)进行 strcat。

所以对于第一个例子:

1.) 读入第一行,提前读到第二行,看看它们是一个空格,然后 strcat 两个字符串,生成"First linesecond line"(对遵循此模式的任何其他行重复)。

这是我的尝试:

int main(void) {
    FILE * file = fopen("file.txt","r");

    if(file==NULL) { return 0; }

    char * fileBuffer = malloc(sizeof(char)*100);
    char * temp = malloc(sizeof(char)*100);

    while(fgets(fileBuffer,100,file) != NULL) {
        if(isspace(fileBuffer[0])) {

            strcpy(temp,fileBuffer);

            //store line that has a space in static temporary variable
        }
        else {
            if(strcmp(temp,"") != 0) { //if temp is not empty
                strcat(fileBuffer,temp);
            }
        }
    }
    free(fileBuffer);
    free(temp);

    return 0;
}

但是这不起作用。发生的情况是当 fgets 被执行时,它读取第一行,发现没有空白,然后转到下一行,看到有空白,存储它,但现在 fileBuffer 不再包含第一行,但第二个。

所以当我下次strcat时,我没有得到“第一行第二行”的正确结果。

相反,我得到了第三行与第二行混合的结果,这不是我想要的。

我不确定如何在这里修正我的逻辑,有什么想法吗?

【问题讨论】:

  • 使用memset()fileBuffer设置为0作为while循环的最后一条语句。
  • temp 可能不足以容纳整个fileBuffer
  • 我已经修复了 temp 的分配。 Sourav 我也不太清楚你所说的“在 while 循环的最后”是什么意思。
  • static char * temp = malloc(sizeof(char)*100); 不是合法的标准 C。那么你使用的是什么编译器?
  • 发布代码 if(isspace(fileBuffer[0]) { 不可编译 - 发布真实代码。

标签: c file parsing strcat


【解决方案1】:

像这样修正你的逻辑:

#define LINE_SIZE 100

int main(void) {
    FILE * file = fopen("file.txt","r");

    if(file==NULL) { perror("fopen"); return -1; }

    char * fileBuffer = malloc(LINE_SIZE);
    char * temp = malloc(LINE_SIZE * 2);//Binding of the string is only once

    while(fgets(fileBuffer, LINE_SIZE, file) != NULL) {
        if(isspace(fileBuffer[0])) {
            temp[strcspn(temp, "\n")] = 0;//remove newline
            strcat(temp, &fileBuffer[1]);
            printf("%s", temp);
        }
        else {
            strcpy(temp, fileBuffer);
        }
    }
    fclose(file);
    free(fileBuffer);
    free(temp);

    return 0;
}

【讨论】:

  • 那么这里的if语句中,&fileBuffer[1]就是代码的下一行?
  • @TTED 跳到空白字符的开头。如果你想要"First line second line",请将&fileBuffer[1] 更改为fileBuffer
  • @BLUEPIXY 为了本网站的初学者的利益,请说明您更改了什么
  • 主要因素是顺序。 strcmp(temp,"") != 0 也不需要。 (原码不能用)
  • return -1;: 0 表示成功,因为需要不同的值。
【解决方案2】:

您还有几个需要处理的额外注意事项。首先,您需要删除fgets 读取的尾随'\n'。为此,您将需要读取的行的长度。然后,您可以通过用 nul-terminating 字符覆盖试用版 '\n' 来删除它。例如:

while (fgets (buf1, MAXC, fp)) {
    size_t len1 = strlen (buf1);  /* get length */
    if (len1 && buf1[len1-1] == '\n') buf1[--len1] = 0; /* remove \n */

另一个考虑因素是如何管理用于组合线路的内存的分配和释放。由于您正在从相对固定长度的字符串中读取最后一行的 first partsecond part,因此使用 2 个静态缓冲区(一个用于读取)会更有意义行,一个用于持有第一个副本。您可以为最终结果分配。例如

enum { MAXC = 100 };  /* constant for max characters */
...
int main (int argc, char **argv) {

    char buf1[MAXC] = {0};
    char buf2[MAXC] = {0};
    char *both = NULL;

一旦您准备好将生产线的两个部分组合起来,您就可以准确分配所需的空间,例如

        if (*buf1 == ' ' && *buf2) {
            both = malloc (len1 + strlen (buf2) + 1);
            strcpy (both, buf2);
            strcat (both, buf1);
            ...

每次分配后不要忘记free both。将各个部分放在一起,并修正比较的逻辑,您最终可能会得到如下解决方案:

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

enum { MAXC = 100 };

int main (int argc, char **argv) {

    char buf1[MAXC] = {0};
    char buf2[MAXC] = {0};
    char *both = NULL;
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    if (!fp) {
        fprintf (stderr, "error: file open failed '%s'.\n,", argv[1]);
        return 1;
    }

    while (fgets (buf1, MAXC, fp)) {
        size_t len1 = strlen (buf1);
        if (len1 && buf1[len1-1] == '\n') buf1[--len1] = 0;
        if (*buf1 == ' ' && *buf2) {
            both = malloc (len1 + strlen (buf2) + 1);
            strcpy (both, buf2);
            strcat (both, buf1);
            printf ("'%s'\n", both);
            free (both);
            *buf2 = 0;
        }
        else
            strcpy (buf2, buf1);
    }
    if (fp != stdin) fclose (fp);

    return 0;
}

输出

$ ./bin/cpcat ../dat/catfile.txt
'First line second line'
'Third line fourth line'

查看一下,如果您有任何问题,请告诉我。

【讨论】:

  • 当然你知道我不是fgets (buf1, MAXC, fp)) { size_t len1 = strlen (buf1); buf1[len1-1] = 0; 的粉丝,因为这是一个黑客利用,使第一个char fgets() 读取一个空字符。 other ideas 此外,文件的最后一行可能没有\n
  • 是的,我很感激。目的是不要偏离串联兔子路径太远。但是,您是 100% 正确的。应该包括对if (len1) 的一般检查,并且对作为newline 的最后一个字符的正常检查也应该在那里。固定:)
【解决方案3】:

真是一种又快又脏的方法

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

int main(void) {

    FILE * file = fopen("file.txt", "r");

    if (file == NULL) { return 0; }

    char fileBuffer[100];
    char temp[100];
    int first = 1;

    while (fgets(fileBuffer, 100, file) != NULL) {
        if (isspace(fileBuffer[0])) {

            strcat(temp, fileBuffer);
            //store line that has a space in static temporary variable
        }
        else {
            if (first == 1){
                strncpy(temp, fileBuffer, sizeof(temp));

                // Remove the end line
                temp[strlen(temp) - 1] = 0;
                strcat(temp, " ");
                first = 0;
            }
            else{
                if (strcmp(temp, "") != 0) { //if temp is not empty
                    strcat(temp, fileBuffer);

                    // Remove the end line
                    temp[strlen(temp) - 1] = 0;
                    strcat(temp, " ");
                }

            }

        }
    }
    printf("%s", temp);
    free(fileBuffer);
    free(temp);

    return 0;
}

输出:

【讨论】:

  • char temp[100]; ... strcat(temp, fileBuffer); 连接到未初始化的数组temp
  • 第一次去strncpy(temp, fileBuffer, sizeof(temp));
  • 只有当第一行不以空格开头时,才会发生“第一次它将变为 strncpy”。代码无法控制的东西。
  • 确实如此。我只是根据他的输入写了一个答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多