K&R C语言编程:EX 3.3

K&R Programming in C: EX 3.3

EX 3.3: 编写函数 expand(s1,s2) 将字符串 s1 中的 shorthand 符号如 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] != '[=10=]'; ++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] = '[=10=]';
}

它成功扩展了任何范围,只要它不在任何其他范围之后,即。在第一个范围完成后,它不会向 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

任何人都可以指出正确的方向来纠正我的错误吗?
谢谢。

在你的内部 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--;

正如 dbush 所建议的,您需要做一个 j--,但是对于像 a-c-g 这样的情况,您也需要改变您的内在 for 条件。不用检查 c <= s1[i+2],你只需要检查到 c < 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] != '[=10=]'; ++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] = '[=10=]';
}

P.S:此代码解决了 OP 手头的直接问题(即原始 post 中显示的输入)。但是,对于 a-b-c- 这样的输入,此代码会失败。 abc-DEFabc--defabc-456 等输入也需要额外的代码。但是,正如评论中所见(关于这个答案),OP 希望自己解决这些问题。

由于 sps 和 dbush 已经使它起作用,让我也加两分钱。

如果可能,您应该使您的内容简单易读。例如:您在循环中加载了太多内容,而不是 IOCCC。 Increment/decrement 只有您在 for 循环的第一部分中定义的索引。在您的情况下,这将是变量 ic 。对向量 s1s2 的迭代应该尽可能接近向量。

这给出:

void expand(char s1[], char s2[]){
    int i;
    int j;
    char c;
    for(i = 0, j = 0; s1[i] != '[=10=]'; 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] = '[=10=]';
}

那样做可以去掉其他必要的修正 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 年了。