Linux实现reverse


OSTEP项目二:github测试文件代码

这个就一个功能:reverse。

prompt> ./reverse
prompt> ./reverse input.txt
prompt> ./reverse input.txt output.txt

输入:(可以是文件,也可以是stdin):

hello
this
is 
a file

输出:(可以是文件,也可以是stdout):

a file
is
this
hello

总体感觉这个项目还挺有练习效果,建议做做,里面主要有几个点:

  • 每行可能任意多个字符,那最好做一下动态扩容。
  • 反转行,用栈的思路写比较方便,没必要写个通用栈(pushpop之类的),结合具体应用就行。
  • 文件为同一个文件要报错退出,问题?怎么判断同一文件?文件名?那link呢?
// stack
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

typedef struct strInStack
{
    char *str;
    struct strInStack *next;
    struct strInStack *before;
} strInStack;

typedef struct
{
    strInStack *tail;
    int size;
} distack;

void assertMalloc(char *buf)
{
    if (buf == NULL)
    {
        fprintf(stderr, "malloc failed\n");
        exit(1);
    }
}

int readOneline(distack *stack, FILE *fpin)
{
    // 动态扩容,开辟了最后再释放,作为缓冲
    char *buf = (char *)malloc(sizeof(char) * 129);
    assertMalloc(buf);
    int bufSize = 128;
    int i = 0;
    int nread;
    for (;;)
    {
        nread = fread(buf + i, 1, 1, fpin);

        if (nread == 0)
        {
            buf[i] = 0;
            break;
        }
        if (buf[i] == '\n')
        {
            buf[i + 1] = 0;
            break;
        }
        i++;
        // 容量不够了,2倍扩容
        if (i == bufSize)
        {
            bufSize *= 2;
            char *newbuf = (char *)malloc(sizeof(char) * (bufSize + 1));
            assertMalloc(newbuf);
            strncpy(newbuf, buf, i);
            free(buf);
            buf = newbuf;
            newbuf = NULL;
        }
    }
    strInStack *sis = (strInStack *)malloc(sizeof(strInStack));
    if (sis == NULL)
    {
        fprintf(stderr, "bad malloc\n");
        exit(1);
    }
    sis->str = buf;
    sis->before = NULL;
    sis->next = NULL;
    if (stack->size == 0)
    {
        stack->tail = sis;
        stack->size = 1;
        return 0;
    }
    sis->before = stack->tail;
    stack->tail->next = sis;
    stack->tail = sis;
    stack->size += 1;
    if (nread == 0)
        return 1; //文件末尾
    return 0;
}

void popAllStack(distack *stack, FILE *fpout)
{
    strInStack *sis = stack->tail;
    while (stack->size > 0)
    {
        fprintf(fpout, "%s", sis->str);
        free(sis->str);
        sis = sis->before;
        free(stack->tail);
        stack->tail = sis;
        stack->size--;
    }
}

int main(int argc, char **argv)
{
    if (argc > 3)
    {
        fprintf(stderr, "usage: reverse <input> <output>\n");
        exit(1);
    }
    FILE *fpin = stdin;
    FILE *fpout = stdout;

    if (argc >= 2)
    {
        fpin = fopen(argv[1], "r");
        if (fpin == NULL)
        {
            fprintf(stderr, "reverse: cannot open file '%s'\n", argv[1]);
            exit(1);
        }
        if (argc == 3)
        {
            // 不能仅通过文件名判断为统一文件,也可能是符号链接或者硬链接
            // if(strcmp(argv[1],argv[2])==0)
            // {
            //     fprintf(stderr,"reverse: input and output file must differ\n");
            //     exit(1);
            // }
            //应通过文件节点是否相同来判断
            struct stat file1;
            struct stat file2;
            stat(argv[1], &file1);
            stat(argv[2], &file2);
            if ((file1.st_dev == file2.st_dev) && (file1.st_ino == file2.st_ino))
            {
                fprintf(stderr, "reverse: input and output file must differ\n");
                exit(1);
            }

            fpout = fopen(argv[2], "w");
            if (fpout == NULL)
            {
                fprintf(stderr, "reverse: cannot open file '%s'\n", argv[2]);
                exit(1);
            }
        }
    }
    int state;
    distack *stack = (distack *)malloc(sizeof(distack));
    if (stack == NULL)
    {
        fprintf(stderr, "bad malloc\n");
        exit(1);
    }
    for (;;)
    {
        state = readOneline(stack, fpin);
        if (state == 1)
            break;
    }
    popAllStack(stack, fpout);
    free(stack);
    return 0;
}

image-20210817161512107