首页 > 解决方案 > 我正在尝试在 C 中创建一个代码抛光程序

问题描述

我正在尝试创建函数delete_comments()。给出了read_file()main函数。

实现char *delete_comments(char *input)从存储在输入处的程序中删除 C 注释的功能。输入变量指向动态分配的内存。该函数返回指向抛光程序的指针。您可以为输出分配一个新的内存块,或者直接在输入缓冲区中修改内容。

您需要处理两种类型的评论:

/*由和分隔的传统块注释*/。这些注释可能跨越多行。您应该只删除开始/*和结束的字符*/,例如,保持任何后续换行符不变。

行注释从//换行符开始。在这种情况下,也必须删除换行符。

调用的函数delete_comments()仅处理来自delete_comments(). 它不为任何指针分配内存。实现delete_comments()函数的一种方法是为目标字符串分配内存。但是,如果分配了新内存,则输入中的原始内存必须在使用后释放。

我无法理解为什么我目前的方法是错误的,或者我得到奇怪输出的具体问题是什么。我通过尝试创建一个新数组来解决问题,在该数组中使用新规则复制输入字符串。

#include "source.h"

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

/* Remove C comments from the program stored in memory block <input>.
 * Returns pointer to code after removal of comments.
 * Calling code is responsible of freeing only the memory block returned by
 * the function.
 */
char *delete_comments(char *input)
{
    input = malloc(strlen(input) * sizeof (char));
    char *secondarray = malloc(strlen(input) * sizeof (char));

    int x, y = 0;

    for (x = 0, y = 0; input[x] != '\0'; x++) {
        if ((input[x] == '/') && (input[x + 1] == '*')) {
            int i = 0;
            while ((input[x + i] != '*') && (input[x + i + 1] != '/')) {
                y++;
                i++;
            }
        }

        else if ((input[x] == '/') && (input[x + 1] == '/')) {
            int j = 0;
            while (input[x + j] != '\n') {
                y++;
                j++;
            }
        }

        else  {
            secondarray[x] = input[y];
            y++;
        }
    }

    return secondarray;
}


/* Read given file <filename> to dynamically allocated memory.
 * Return pointer to the allocated memory with file content, or
 * NULL on errors.
 */
char *read_file(const char *filename)
{
    FILE *f = fopen(filename, "r");
    if (!f)
        return NULL;
    
    char *buf = NULL;
    unsigned int count = 0;
    const unsigned int ReadBlock = 100;
    unsigned int n;
    do {
        buf = realloc(buf, count + ReadBlock + 1);
        n = fread(buf + count, 1, ReadBlock, f);
        count += n;
    } while (n == ReadBlock);
    
    buf[count] = 0;
    
    return buf;
}


int main(void)
{
    char *code = read_file("testfile.c");
    if (!code) {
        printf("No code read");
        return -1;
    }
    printf("-- Original:\n");
    fputs(code, stdout);

    code = delete_comments(code);
    printf("-- Comments removed:\n");
    fputs(code, stdout);
   
    free(code);
}

标签: c

解决方案


您的程序存在基本问题。

  1. 它无法对输入进行标记。注释开始序列可以出现在字符串文字中,在这种情况下,它们不表示注释: "/* not a comment"

  2. 你有一些基本的错误:

     if ((input[x] == '/') && (input[x + 1] == '*')) {
         int i = 0;
         while ((input[x + i] != '*') && (input[x + i + 1] != '/')) {
             y++;
             i++;
         }
     }
    

    在这里,当我们进入循环时, withi = 0仍然input + x指向开头的/。我们没有跳过开头*,并且已经在寻找结尾*。这意味着该序列/*/将被识别为完整的评论,但事实并非如此。

    此循环还假定每个/*评论都已正确关闭。它不检查可以终止输入的空字符,因此如果注释未关闭,它将超出缓冲区的末尾。

  3. C 有续行。在 ISO C 翻译阶段 2 中,删除所有反冲换行序列,将一个或多个物理行转换为逻辑行。这意味着//注释可以跨越多个物理行:

     // this is an \
     extended comment
    

    顺便说一句,您可以看到 StackOverflow 的语法高亮自动语言检测器做得很好!

    行延续独立于标记化,直到翻译阶段 3 才会发生。这意味着:

     /\
     /\
     this is an extended \
     comment
    

    那个已经打败了 StackOverflow 的语法高亮。此外,任何记号都可能发生续行,可能发生多次:

     "\
     this is a string literal\
     "
    

推荐阅读