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-c
和 a-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-DEF
、abc--def
、abc-456
等输入也需要额外的代码。但是,正如评论中所见(关于这个答案),OP 希望自己解决这些问题。
由于 sps 和 dbush 已经使它起作用,让我也加两分钱。
如果可能,您应该使您的内容简单易读。例如:您在循环中加载了太多内容,而不是 IOCCC。 Increment/decrement 只有您在 for 循环的第一部分中定义的索引。在您的情况下,这将是变量 i
和 c
。对向量 s1
和 s2
的迭代应该尽可能接近向量。
这给出:
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 年了。
EX 3.3: 编写函数 expand(s1,s2)
将字符串 s1 中的 shorthand 符号如 a-z 扩展到等效的完整列表 abc...xyz in s2
允许字母大小写和数字,并且准备好处理像 a-b-c
和 a-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-DEF
、abc--def
、abc-456
等输入也需要额外的代码。但是,正如评论中所见(关于这个答案),OP 希望自己解决这些问题。
由于 sps 和 dbush 已经使它起作用,让我也加两分钱。
如果可能,您应该使您的内容简单易读。例如:您在循环中加载了太多内容,而不是 IOCCC。 Increment/decrement 只有您在 for 循环的第一部分中定义的索引。在您的情况下,这将是变量 i
和 c
。对向量 s1
和 s2
的迭代应该尽可能接近向量。
这给出:
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 年了。