C中如何优雅地遍历一个字符串到最后
How to gracefully traverse a string in C to the end
我正在开发一个 C 函数,它必须输入一个字符串并仅删除开头的所有非字母字符。例如,如果输入字符串是 "123 456 My dog has fleas."
那么输出字符串必须是:"My dog has fleas."
这是我所拥有的,适用于上面的示例:
int isALetter(char x){
// Checks to see is x is an ASCII letter
if( ((int)x>=65 && (int)x<=90) || ((int)x>=97 && (int)x<=122) )
return 0; // TRUE
return 1; // FALSE
}
char* removeNonLettersAtBeginning(char* str){
while( isALetter(str[0]) == 1 && &str[0] != NULL )
str++;
return str;
}
这就是让我烦恼的地方...如果字符串根本没有字母,代码似乎不起作用。如果我提交字符串 " "
(没有字母),那么我会得到“XDG_SESSION_ID=3818
”。我不知道那个字符串是什么,但我假设它在系统中是 "garbage"。
但是我的 removeNonLettersAtBeginning()
函数应该返回一个“”字符串,一个空字符串。我不知道问题出在哪里,但我敢打赌它出在这里:
while( isALetter(str[0]) == 1 && &str[0] != NULL )
该行的 "&str[0] != NULL"
部分是为了确保我不会 运行 超出字符串的末尾;我正在尝试检查是否遇到了终止字符串的 Null 字符。有人看到我哪里出错了吗?
你检查的空终止符是错误的,空终止符是 '[=11=]'
而不是 NULL
#include <stdio.h>
int isALetter(char x){
// Checks to see is x is an ASCII letter
if( (x>='A' && x<='Z') || (x>='a' && x<='z') )
return 0; // TRUE
return 1; // FALSE
}
char* removeNonLettersAtBeginning(char* str){
if (str != NULL)
{
while( isALetter(*str) == 1 && *str != '[=10=]' )
str++;
}
return str;
}
int main (void)
{
char test_string[] = " test\n";
char *test_ptr = test_string;
printf ("%s", test_ptr);
test_ptr = removeNonLettersAtBeginning(test_ptr);
printf ("%s", test_ptr);
}
附带说明一下,为了使您的代码更具可读性,请避免使用像 65
、90
这样的幻数。
如图所示,您可以轻松地使用字符来执行此操作:'A'
、'Z'
...
你写:
while( isALetter(str[0]) == 1 && &str[0] != NULL ) //error in str[0]
str++; //it must be *str
在这里,你使用了 char * str ,它将指向要测试的字符串。
如您所说,您想要从字符串中删除所有 non-characters。
但是,你用错了 char 类型的指针。
无错误代码:
while( isALetter(*str) == 1 && *str != '[=11=]')
str++;
它应该对你有用:)
这是另一种方法。
#include <ctype.h>
...
void stripNonAlpha( char *str )
{
size_t r = 0, w = 0; // read and write indices
/**
* Find the first alpha character in the string
*/
while ( str[r] && !isalpha( str[r] ) )
r++;
/**
* Shift remaining characters to the left, including the 0 terminator
*/
while ( (str[w++] = str[r++] ) )
; //empty loop
}
基本上,此代码搜索字符串中的第一个字母字符;一旦找到,该字符和所有后续字符将被复制到字符串的初始部分。例如,让我们以字符串 "123 test"
为例。最初,一切都是这样的:
r
|
v
+---+---+---+---+---+---+---+---+---+
|'1'|'2'|'3'|' '|'t'|'e'|'s'|'t'| 0 |
+---+---+---+---+---+---+---+---+---+
^
|
w
第一个循环检查索引r
处字符的值;虽然它既不是字符串的结尾也不是字母字符,但前进 r
。在循环结束时,我们有这个:
r
|
v
+---+---+---+---+---+---+---+---+---+
|'1'|'2'|'3'|' '|'t'|'e'|'s'|'t'| 0 |
+---+---+---+---+---+---+---+---+---+
^
|
w
第二个循环从 r
复制字符并将它们写入 w
(直到并包括 0 终止符),如下所示:
r
|
v
+---+---+---+---+---+---+---+---+---+
|'t'|'2'|'3'|' '|'t'|'e'|'s'|'t'| 0 |
+---+---+---+---+---+---+---+---+---+
^
|
w
r
|
v
+---+---+---+---+---+---+---+---+---+
|'t'|'e'|'3'|' '|'t'|'e'|'s'|'t'| 0 |
+---+---+---+---+---+---+---+---+---+
^
|
w
r
|
v
+---+---+---+---+---+---+---+---+---+
|'t'|'e'|'s'|' '|'t'|'e'|'s'|'t'| 0 |
+---+---+---+---+---+---+---+---+---+
^
|
w
r
|
v
+---+---+---+---+---+---+---+---+---+
|'t'|'e'|'s'|'t'|'t'|'e'|'s'|'t'| 0 |
+---+---+---+---+---+---+---+---+---+
^
|
w
r
|
v
+---+---+---+---+---+---+---+---+---+
|'t'|'e'|'s'|'t'| 0 |'e'|'s'|'t'| 0 |
+---+---+---+---+---+---+---+---+---+
^
|
w
一些示例输出:
$ ./stripper "123 345 this is a test"
before: "123 345 this is a test"
after: "this is a test"
$ ./stripper "this is a test"
before: "this is a test"
after: "this is a test"
$ ./stripper " "
before: " "
after: ""
$ ./stripper "12345"
before: "12345"
after: ""
$ ./stripper "12345 abc 23456"
before: "12345 abc 23456"
after: "abc 23456"
显然,这个操作是破坏性的——输入的字符串被修改了。如果您不希望这样,则需要写入不同的目标字符串。这应该很容易弄清楚,通过。
我正在开发一个 C 函数,它必须输入一个字符串并仅删除开头的所有非字母字符。例如,如果输入字符串是 "123 456 My dog has fleas."
那么输出字符串必须是:"My dog has fleas."
这是我所拥有的,适用于上面的示例:
int isALetter(char x){
// Checks to see is x is an ASCII letter
if( ((int)x>=65 && (int)x<=90) || ((int)x>=97 && (int)x<=122) )
return 0; // TRUE
return 1; // FALSE
}
char* removeNonLettersAtBeginning(char* str){
while( isALetter(str[0]) == 1 && &str[0] != NULL )
str++;
return str;
}
这就是让我烦恼的地方...如果字符串根本没有字母,代码似乎不起作用。如果我提交字符串 " "
(没有字母),那么我会得到“XDG_SESSION_ID=3818
”。我不知道那个字符串是什么,但我假设它在系统中是 "garbage"。
但是我的 removeNonLettersAtBeginning()
函数应该返回一个“”字符串,一个空字符串。我不知道问题出在哪里,但我敢打赌它出在这里:
while( isALetter(str[0]) == 1 && &str[0] != NULL )
该行的 "&str[0] != NULL"
部分是为了确保我不会 运行 超出字符串的末尾;我正在尝试检查是否遇到了终止字符串的 Null 字符。有人看到我哪里出错了吗?
你检查的空终止符是错误的,空终止符是 '[=11=]'
而不是 NULL
#include <stdio.h>
int isALetter(char x){
// Checks to see is x is an ASCII letter
if( (x>='A' && x<='Z') || (x>='a' && x<='z') )
return 0; // TRUE
return 1; // FALSE
}
char* removeNonLettersAtBeginning(char* str){
if (str != NULL)
{
while( isALetter(*str) == 1 && *str != '[=10=]' )
str++;
}
return str;
}
int main (void)
{
char test_string[] = " test\n";
char *test_ptr = test_string;
printf ("%s", test_ptr);
test_ptr = removeNonLettersAtBeginning(test_ptr);
printf ("%s", test_ptr);
}
附带说明一下,为了使您的代码更具可读性,请避免使用像 65
、90
这样的幻数。
如图所示,您可以轻松地使用字符来执行此操作:'A'
、'Z'
...
你写:
while( isALetter(str[0]) == 1 && &str[0] != NULL ) //error in str[0]
str++; //it must be *str
在这里,你使用了 char * str ,它将指向要测试的字符串。
如您所说,您想要从字符串中删除所有 non-characters。 但是,你用错了 char 类型的指针。
无错误代码:
while( isALetter(*str) == 1 && *str != '[=11=]')
str++;
它应该对你有用:)
这是另一种方法。
#include <ctype.h>
...
void stripNonAlpha( char *str )
{
size_t r = 0, w = 0; // read and write indices
/**
* Find the first alpha character in the string
*/
while ( str[r] && !isalpha( str[r] ) )
r++;
/**
* Shift remaining characters to the left, including the 0 terminator
*/
while ( (str[w++] = str[r++] ) )
; //empty loop
}
基本上,此代码搜索字符串中的第一个字母字符;一旦找到,该字符和所有后续字符将被复制到字符串的初始部分。例如,让我们以字符串 "123 test"
为例。最初,一切都是这样的:
r
|
v
+---+---+---+---+---+---+---+---+---+
|'1'|'2'|'3'|' '|'t'|'e'|'s'|'t'| 0 |
+---+---+---+---+---+---+---+---+---+
^
|
w
第一个循环检查索引r
处字符的值;虽然它既不是字符串的结尾也不是字母字符,但前进 r
。在循环结束时,我们有这个:
r
|
v
+---+---+---+---+---+---+---+---+---+
|'1'|'2'|'3'|' '|'t'|'e'|'s'|'t'| 0 |
+---+---+---+---+---+---+---+---+---+
^
|
w
第二个循环从 r
复制字符并将它们写入 w
(直到并包括 0 终止符),如下所示:
r
|
v
+---+---+---+---+---+---+---+---+---+
|'t'|'2'|'3'|' '|'t'|'e'|'s'|'t'| 0 |
+---+---+---+---+---+---+---+---+---+
^
|
w
r
|
v
+---+---+---+---+---+---+---+---+---+
|'t'|'e'|'3'|' '|'t'|'e'|'s'|'t'| 0 |
+---+---+---+---+---+---+---+---+---+
^
|
w
r
|
v
+---+---+---+---+---+---+---+---+---+
|'t'|'e'|'s'|' '|'t'|'e'|'s'|'t'| 0 |
+---+---+---+---+---+---+---+---+---+
^
|
w
r
|
v
+---+---+---+---+---+---+---+---+---+
|'t'|'e'|'s'|'t'|'t'|'e'|'s'|'t'| 0 |
+---+---+---+---+---+---+---+---+---+
^
|
w
r
|
v
+---+---+---+---+---+---+---+---+---+
|'t'|'e'|'s'|'t'| 0 |'e'|'s'|'t'| 0 |
+---+---+---+---+---+---+---+---+---+
^
|
w
一些示例输出:
$ ./stripper "123 345 this is a test"
before: "123 345 this is a test"
after: "this is a test"
$ ./stripper "this is a test"
before: "this is a test"
after: "this is a test"
$ ./stripper " "
before: " "
after: ""
$ ./stripper "12345"
before: "12345"
after: ""
$ ./stripper "12345 abc 23456"
before: "12345 abc 23456"
after: "abc 23456"
显然,这个操作是破坏性的——输入的字符串被修改了。如果您不希望这样,则需要写入不同的目标字符串。这应该很容易弄清楚,通过。