【问题标题】:K&R Programming in C: EX 3.3C 语言中的 K&R 编程:EX 3.3
【发布时间】:2016-07-06 15:40:03
【问题描述】:

EX 3.3:编写一个函数expand(s1,s2),将字符串s1 中的a-z 等速记符号扩展为等效的完整列表abc...xyz in s2 允许大小写字母和数字,并准备处理a-b-ca-z0-9-a-z。安排前导或尾随 - 按字面意思理解。

我正在尝试解决 K&R 中的练习 3.3,这就是我所拥有的:

void expand(char s1[], char s2[]){
    int i; // index for first string
    int j; // index for 2nd string

    for(i = 0, j = 0; s1[i] != '\0'; ++i, ++j){
        if(isalnum(s1[i]) && s1[i+1] == '-'){
            char c = s1[i];
            for(char c = s1[i]; c <= s1[i+2]; ++c, ++j){
                s2[j] = c;
            }
            ++i;
        } else{
            s2[j] = s1[i];
        }
    }
    s2[j] = '\0';
}

它成功地扩展了任何范围,只要它不在任何其他范围之后,即。第一个范围完成后,它不会向 s2 添加任何内容。如果我把这个声明:

printf("%c\n", c);

在第二个 for 循环中,它会打印出正确的字符,但不会将其添加到 s2。

输入和输出示例:

In: akls aldio a-h 19 aodk                                                 
Out: akls aldio abcdefgh

In: 0-6 a-c lol                                                              
Out: 0123456

In: a-c-g 1okd 2-4                                                           
Out: abc

谁能指出我纠正错误的正确方向?
谢谢。

【问题讨论】:

  • 欢迎来到 Stack Overflow!听起来您可能需要学习如何使用调试器来逐步执行代码。使用好的调试器,您可以逐行执行您的程序,并查看它与您期望的偏差在哪里。如果您要进行任何编程,这是必不可少的工具。进一步阅读:How to debug small programs.
  • 我不知道这是否解决了它,但我会从两个for 循环中删除++j,并将它们放在您写入s2[j] 的位置之后,或者更好,使用s2[j++]
  • @WeatherVane 成功了!任何想法为什么?
  • @PaulR 谢谢。我将研究 c 的调试器。我以前用过netbeans内置的,但是c没用过。
  • 正如答案所说。我的建议是在使用点而不是在其他地方增加索引,以使您能够处理逻辑。 @dbush 在我开始之前还提到了i+=2。您必须跳过 2 个字符,而不是一个(第三个在 for 循环中处理。

标签: c gcc kernighan-and-ritchie


【解决方案1】:

在你的内部 for 循环之后,j 是它应该在的位置,所以你跳过写到一个位置。如果该位置恰好包含值 0,它会终止字符串,并且在它之后看不到任何内容。

另外,i 在它应该在的位置之前。

替换这个:

        for(char c = s1[i]; c <= s1[i+2]; ++c, ++j){
            s2[j] = c;
        }
        ++i;

有了这个:

        for(char c = s1[i]; c <= s1[i+2]; ++c, ++j){
            s2[j] = c;
        }
        i+=2;
        j--;

【讨论】:

  • i 只需要加一,这样a-b-c 这样的情况就可以工作。其余的都是正确的。它有效,我明白为什么它不起作用。如果您删除该部分,我会将此答案标记为正确。
【解决方案2】:

正如 dbush 建议的那样,您需要做一个 j--,但对于像 a-c-g 这样的情况,您还需要更改您的内部 for 条件。而不是检查c &lt;= s1[i+2],您只需要检查直到c &lt; s1[i+2]

void expand(char s1[], char s2[]){
    int i; // index for first string
    int j; // index for 2nd string

    for(i = 0, j = 0; s1[i] != '\0'; ++i, ++j){
            if(isalnum(s1[i]) && s1[i+1] == '-'){
                    char c = s1[i];
                    /* Do it c < instead of c<= */
                    for(char c = s1[i]; c < s1[i+2]; ++c, ++j){
                            s2[j] = c;
                    }
                    --j;  /* Decrement j once */
                    ++i; 
            } else {
                    s2[j] = s1[i];
            }
    }
    s2[j] = '\0';
}

P.S:此代码解决了 OP 手头的直接问题(即原始帖子中显示的输入)。但是,对于a-b-c- 之类的输入,此代码会失败。 abc-DEFabc--defabc-456 等输入还需要额外的代码。但是,正如 cmets (of this answer) 中所见,OP 希望自己解决这些问题。

【讨论】:

  • 谢谢。在@dbush 的回答不适用于这些情况后,我意识到并做出了这个改变。
  • 还有一个问题,但是使用此代码,请尝试输入a-g-,这将不起作用...我正在尝试修复它,在发布答案之前我只尝试了您的测试输入
  • 别打扰了。这是我的问题。我还没有完全完成。在我意识到我被困住后,我来到了这里。另外,在您的回答中,您说c &lt; s1[i+1],但我认为您的意思是c &lt; s1[1+2]
  • 是的,我的意思是c &lt; s1[i+2],从代码中可以看出。
  • 这个问题很好。我可以在这里向您建议一些好的输入。其中一些是'abc-Def','abc-456','abc--def',除了通常的......上面的代码失败了..希望你能修复它们,如果你需要任何指针,你可以味精回到这里....
【解决方案3】:

sps 和 dbush 已经成功了,让我也加两分钱。

如果可能的话,你应该让你的东西简单易读。例如:您在循环中加载了太多内容,而不是 IOCCC。仅增加/减少您在 for 循环的第一部分中定义的索引。在您的情况下,这将是变量 ic。向量s1s2 上的迭代应该尽可能接近向量。

这给了:

void expand(char s1[], char s2[]){
    int i;
    int j;
    char c;
    for(i = 0, j = 0; s1[i] != '\0'; i++){
        if(isalnum(s1[i]) && s1[i+1] == '-'){
            for(c = s1[i]; c < s1[i+2]; c++){
                s2[j++] = c;
            }
            i++;
        } else{
            s2[j++] = s1[i];
        }
    }
    s2[j] = '\0';
}

这样做可以消除其他必要的更正j--

测试一下:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char **argv)
{
  char s[200];
  char s2[200];
  int i;
  memset(s,0,200);
  memset(s2,0,200);
  // put some spaces in between the arguments
  for(i=1;i<argc;i++){
    // counting ommitted!
    strcat(s2,argv[i]);
    s2[strlen(s2)] = ' ';
  }
  printf("In:  %s\n",s2);
  expand(s2,s);
  printf("Out: %s\n",s);
  exit(EXIT_SUCCESS);
}

$ gcc -W -Wall -std=c11  expand.c -o expand
./expand 0-9 ASD a-z QWE a-ch-r
In:  0-9 ASD a-z QWE a-c-r 
Out: 0123456789 ASD abcdefghijklmnopqrstuvwxyz QWE abchijklmnopqr

哦,还有++i 等人。在 for 循环的第三部分:我们现在有 2016 年。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-21
    • 2013-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多