C I / O和字符串解析 - 行为不规律

时间:2012-03-23 01:17:42

标签: c io string-parsing

我的函数从文本文件中解析段 使用开始和结束字符串(参见main()) 并将段保存在单独的文件中。

我不知道它有什么问题,但它会返回这3个段文件:

  

1 START_TEXT_END
2 _START_BLABLUB_END
3开始4结束

输入test.txt(4个START ... END段):

  

_START_TEXT_END_START_BLABLUB_END_
  _START_THIRD_END START 4 END

应该包含“START”和“END”,但缺少第3段(“START_THIRD_END”) 并且2.段错误地包括“_”。对于其他输入文件,它也会返回不准确的结果。 有什么想法吗?

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

long split(char *filename, char *segment_filename, char *str_start, char *str_end, long n_start, long n_end) {
    long segments = 0, size_segment = 0;
    FILE *file = fopen(filename, "rb"), *segmentfile;
    long size_str_start = strlen(str_start);
    long size_str_end = strlen(str_end);
    long pos_str_start = 0;
    long pos_str_end = 0;
    int chr;
    char *segment_filename_numbered;
    char *segment = (char*)malloc(1);
    fseek(file,0,0);

    if (file) {
        while ( (chr = fgetc(file)) != EOF && !feof(file) && !ferror(file)) {
            size_segment++;

            // scan for start string
            if ( chr == str_start[pos_str_start] ) { pos_str_start++; }
            else pos_str_start = 0;
            if ( pos_str_start == size_str_start )
            size_segment = size_str_start, pos_str_start = 0;

            // scan for end string
            if ( chr == str_end[pos_str_end] ) pos_str_end++;
            else pos_str_end = 0;

            if ( pos_str_end == size_str_end )
            {
                pos_str_end = 0;
                segments++;
                if (segments > n_start) {
                    segment = (char*) realloc(segment, size_segment);
                    //segment_filename_numbered = chars_cat2( segment_filename, chars_number(segments,     '0', 8, 16) ); // SOME OF MY LIBRARY FUNCTIONS
                    segment_filename_numbered = ltoa(segments, segment_filename_numbered, 10);
                    fseek(file, -size_segment, SEEK_CUR);
                    fread(segment, size_segment, 1, file);
                    segmentfile = fopen(segment_filename_numbered, "wb");
                    fwrite(segment, size_segment, 1, segmentfile);
                    fseek(file, size_segment, SEEK_CUR);
                    fclose(segmentfile);
                }
            }
        }

        fclose(file);
    }

    return segments;
}


int main(int argc, char* argv[])
{
    split("test.txt", "test_", "START", "END", 0, 0);
    system("Pause");
    return 0;
}

我是新来的,手动在每行前面添加4个空格是一场噩梦,标记代码的简单方法是什么?

4 个答案:

答案 0 :(得分:1)

可能还有其他问题,但有一个确定错误就是来电:

segment_filename_numbered = ltoa(segments, segment_filename_numbered, 10);

segment_filename_numbered 被定义为指针,但需要是一个足够大的缓冲区来保存数字的字符串表示

char segment_filename_numbered[16];
ltoa(segments, segment_filename_numbered, 10);

我以前没见过ltoa。我通常会使用snprintf,它允许您声明缓冲区大小以避免溢出。

修改

没有任何冒犯意味着,但是你正试图试图调试这个程序。我的建议是你调查标准库字符串函数(strstr,strchr等)并重写程序,一次读取多个char。该程序是否有一个应用程序 - 换句话说它是在某个地方/由某人使用 - 还是一个练习?

答案 1 :(得分:1)

好的,这次我想到了。 问题是这一行:

fseek(file, size_segment, SEEK_CUR);

不需要,因为行“fread(segment,size_segment,1,file);”已经移动了size_segment字节的文件位置。事实上你在这里加倍了。这就是你跳过字符的原因(尝试在每次循环运行时打印chr的值,它会跳过字符)

答案 2 :(得分:0)

该行

while ( (chr = fgetc(file)) != EOF && !feof(file) ...

有点奇怪。一个测试或另一个测试就足够了,但没关系。

我希望你不介意,但我试着按照我写的风格组织程序,看看我是否能看到一个bug。它帮助我阅读了它,但我没有看到任何新的错误,只有William Morris的: - (

我想我可能会试图'fseek 0'来获取开始和结束的文件位置,即使它不那么有效。至少它可能有助于调试它? - )

它可能会帮助其他人遵循它。如果我犯了一个错误,那可能是一个不明显的领域。

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

long split(char *filename, char *segment_filename, 
           char *str_start, char *str_end, 
           long n_start, long n_end) {
    long segments = 0, size_segment = 0;
    FILE *file, *segmentfile;
    long size_str_start = strlen(str_start);
    long size_str_end = strlen(str_end);
    long pos_str_start = 0;
    long pos_str_end = 0;
    int chr;
    char *segment_filename_numbered;
    char *segment = (char*)malloc(1);
    // fseek(file,0,0);
    enum {LOOKING_FOR_START, LOOKING_FOR_END, MATCHED_MARKERS } 
         state = LOOKING_FOR_START;

    if ((file=fopen(filename, "rb")) == NULL) {
        fprintf(stderr, "Error: can't open file %s\n", filename);
        return 0;
    }

    while ( (chr = fgetc(file)) != EOF && !feof(file) && !ferror(file)) {
        size_segment++;

        switch (state) {
            case LOOKING_FOR_START:
                // scan for start string
                if ( chr == str_start[pos_str_start] ) { pos_str_start++; }
                else pos_str_start = 0;
                if ( pos_str_start == size_str_start ) {
                    size_segment = size_str_start; 
                    pos_str_start = 0;
                    state = LOOKING_FOR_END;
                }
                break;
            case LOOKING_FOR_END:
                // scan for end string
                if ( chr == str_end[pos_str_end] ) pos_str_end++;
                else pos_str_end = 0;
                if ( pos_str_end == size_str_end )
                {
                    pos_str_end = 0;
                    state = MATCHED_MARKERS;
                }
                break;
            case MATCHED_MARKERS:
                segments++;
                if (segments > n_start) {
                    segment = (char*) realloc(segment, size_segment);
                    //segment_filename_numbered = chars_cat2( segment_filename, chars_number(segments,     '0', 8, 16) ); // SOME OF MY LIBRARY FUNCTIONS
                    //*** Error: uninitialised segment_filename_numbered *** 
                    segment_filename_numbered = ltoa(segments, segment_filename_numbered, 10); 
                    fseek(file, -size_segment, SEEK_CUR);
                    fread(segment, size_segment, 1, file);
                    segmentfile = fopen(segment_filename_numbered, "wb");
                    fwrite(segment, size_segment, 1, segmentfile);
                    fseek(file, size_segment, SEEK_CUR);
                    fclose(segmentfile);
                }
                state = LOOKING_FOR_START;
            default:
                fprintf(stderr, "Fatal Error: state has become corrupt, value is %d\n", state);
                break;
        }
    }

    fclose(file);

    return segments;

}


int main(int argc, char* argv[])
{
    split("test.txt", "test_", "START", "END", 0, 0);
    system("Pause");
    return 0;
}

答案 3 :(得分:0)

我认为您的问题在于寻找分隔符之间的数据:

fseek(file,-size_segment,SEEK_CUR);

问题是你回到“size_segment”字节,但你已经阅读了更多:size_segment + size_str_end(段结尾)。 你应该写:

fseek(file, -size_segment - size_str_end,SEEK_CUR);

现在,以这种方式处理数据似乎不是很有效(读取数据,找到结尾,寻找数据,写入文件,然后寻找到先前的位置)。 为什么不在输出文件中读取数据时立即写入数据,并在遇到结束文本时更改输出文件?

如果您首先在循环中搜索开始文本,然后搜索数据(您将其写入文件),同时期望结束文本,那么它会更清晰。在这里,你同时拥有所有东西,很难跟上。