【问题标题】:Faulty solution for K&R exercise 1-19K&R 练习 1-19 的错误解决方案
【发布时间】:2020-06-08 09:39:05
【问题描述】:

上下文:我有 JAVA 编程经验,所以也许这就是阻止我理解问题的原因。练习 1-19 要求编写一个函数 reverse(s) 来反转字符串 s。用它来编写一个程序,一次将其输入反转一行。

注意:我稍微修改了输入参数,使其也取字符数组的长度。

这个方案有问题,如下图。

功能:(YES 和 NO 分别是值为 1 和 0 的常数)

void reverse(char input[],int lim)
{
    char tmp[lim];
    int j , nl_check;
    nl_check = NO;

    for(j=0; j<lim-1 && input[j]!='\0';++j) {
        if(input[j] == '\n') {
            nl_check = YES ;
            break;
        }
    }

    --j;

    int i;
    for(i=0; i<=j ; ++i) {
        tmp[j-i]=input[i];
    }

    if(nl_check==YES) {
        tmp[++i]='\n';
    }
    tmp[++i] = '\0';

    for(i=0; tmp[i]!='\0';++i) {
        input[i] = tmp[i];
    }
    tmp[++i] = '\0';
}

输入:

$cat example
hello
this
is
me
and
code

输出:

     $./a.out < example > output; cat output


    olleh
    sihth
    sih
    h
    emh
    h
    dna


    edoc

    edoc

我感觉它与在函数内部创建一个字符数组有关,因为当我反转它而不在内部创建一个新的字符数组(显然更好的方法)时,它运行良好。但是,我仍然不明白这段代码的问题是什么......

编辑:下面是一个不使用数组创建的工作函数,暗示'/n','/0'不是错误。

    /* Similar to @DNT suggestion, I believe.. this function works.*/
    void reverse(char input[] , int lim)
{
    int j , nl_check;
    nl_check = NO;
    for(j=0; j<lim-1 && input[j]!='\0'; ++j)
    {
    if(input[j] == '\n')
    {
        nl_check = YES ;
        break;
    }
    }

    int i,z;
    char tmp='\0';
    --j;
    for(i=0,z=j; i!=((j+1)/2) ; ++i,--z)
    {
    tmp = input[i];
        input[i] = input[z];
        input[z] = tmp;
    }
    if(nl_check==YES)
    {
    input[++j]='\n';
    }
    input[++j] = '\0';
}

【问题讨论】:

  • 您在向tmp 数组写入任何内容之前调用了printf("%s",tmp);。我也看不出这在 Java 中是如何工作的。
  • printf("%s",tmp); 在函数为其元素分配任何值之前打印tmp。为什么那条线在那里?充其量,它会打印之前调用函数时留在堆栈中的数据。
  • tmp[++i]='\n'; 和第一个tmp[++i]='\0' 可以超出tmp 的末尾。
  • 第二个tmp[++i]='\0'; 不需要,可能会超出tmp 的末尾。也许目的是在input 中放置一个空值,而不是tmp
  • @MikeJalfrezi:现在你根本没有printf。请发帖minimal reproducible example

标签: c arrays function


【解决方案1】:

这是一个例子:

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

void reverse(char a[], int sz)
{
    int k, i,j;
    for (i = 0, j = sz-1; i< sz/2; ++i, --j)
    {
        k = a[j];
        a[j] = a[i];
        a[i] = k;
    }
};

int main() {
  char x[] = "abcdefg\nsecond line\nthird line";
  char *p = strtok(x, "\n");
  while(p)
  {
    reverse(p, strlen(p));
    printf("%s\n", p);
    p = strtok(NULL, "\n");
  }
}

稍作修改,它可以忽略换行符并将其反转为单个字符串。

您的函数测试换行符然后仅反转第一个字符串并返回。 如果只有一个字符串没有换行符或末尾有一个换行符,它将反转它,但是一旦遇到\n,它就会停在那里。 对代码的修改应该在你的函数中包含一个循环,检查你是否到达了字符串的末尾,如果没有,则重复它所做的事情。

将它分成两个函数,每个函数只做一项工作,这样会更容易、更简洁和更好的编码实践。

这是另一个版本,它简化了您的功能,一次完成所有操作:

void reverse(char input[] , int lim)
{
    int i, j, z, start=0;

    for(i=0; start< lim ; i++)
    {
        if (input[i] == '\n' || input[i] == '\0')
        {
            for (j=start, z = i-1; j< start+(i-start+1)/2; j++, z--)
            {
                char tmp = input[j];
                input[j] = input[z];
                input[z] = tmp;
            }
            start = i+1;
        }
    }
}

【讨论】:

  • 谢谢,我相信这与我的备用反向函数的逻辑相似,如果不一样的话。只是我不知道为什么我的第一个函数是错误的。
  • 没有解释的代码不是一个好的答案,也没有解释原始代码有什么问题。
  • @MikeJalfrezi 它有逻辑错误。它不会继续超过以\n 结尾的第一行。您在开始时只检查换行符一次,但在处理第一行之后,您不会循环检查字符串以获取更多信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-25
相关资源
最近更新 更多