这是删除文本中数字的程序。例如 ab98k
-> abk
。
#include <stdio.h>
#include <ctype.h>
// move characters starting at cstr+1 to the left by one position
void move_left(char *cstr)
{
while ((*cstr = *(cstr + 1)))
++cstr;
}
// find the first occurrence of a decimal digit.
// return pointer if found, NULL otherwise
char *find_digit(char *cstr)
{
for ( ; *cstr; ++cstr)
if (isdigit(*cstr))
return cstr;
return NULL; // not found
}
void delete_digits(char *cstr) // remove decimal digits
{
while (cstr = find_digit(cstr))
move_left(cstr);
}
int main()
{
// declare array of SZ characters
enum { SZ = 200 };
char cstr[SZ];
// prepare format string to read at most SZ-1 characters
char format[16];
sprintf(format, "%%%ds", SZ - 1); // ie. "%199s" if SZ == 200
if (scanf(format, cstr)) // if attempted input was successful
{
delete_digits(cstr);
puts(cstr);
}
}
我的问题是:假设我输入 ab98k
void delete_digits( char* cstr ) // remove decimal digits
{
while( ( cstr = find_digit(cstr) ) )
move_left(cstr);
}
在函数“cstr=find digit(cstr)
”中,cstr
是指针吗?
我不明白为什么它必须存储 find_digit
结果,它是一个指向数字的指针,再次指向指针 cstr
?
find_digit函数的结果是这样的,那为什么还要把它存入指针cstr
中呢?
ab98k。 ^
目的是什么?当我更改为 { while( ( find_digit(cstr) ) ) move_left(cstr) ;
程序似乎出错了。
我的第二个问题:
char* find_digit(char* cstr)
{
for (; *cstr; ++cstr)
if (isdigit(*cstr))
return cstr;
return NULL; // not found
}
在这个函数的末尾或者当没有数字时,它会为'ab98k'中的最后一个单词'k'返回NULL,对吗?它会向 delete_digit
函数中的 while
返回 null,这将终止它并返回到 main
?那么 NULL 的目的是终止 for 循环吗?
另一个版本
#include <stdio.h>
#include <stdlib.h>
void deldigit(char *str)
{ char *res = str;
int count=0;
while(*str!='\0')
{
if(*str>='1' && *str<='9')
{ count++;}
else
{*(str-count)=*str; /* want this *str after increment to overwrite *(str-count) */
}
str++;}
*(str - count)= '\0';
printf("%s",res);
}
int main()
{ char str[100];
printf("inset word");
scanf("%s",&str);
deldigit(str);
return 0;
}
最佳答案
第一个问题:如果将数组传递给函数,函数实际上接收到指向该数组的指针。您现在可以修改此指针(指针本身,而不是指向的值)而无需修改原始数组。如果将该指针传递给另一个函数,则实际上传递了该指针的副本,即。 e.如果你修改第二个函数中的新指针,第一个函数的指针根本不受影响。这一点很重要(除其他地方外),尤其是对于从 delete_digits 中调用的 move_left 函数!
然后,您需要重新分配指针以便能够在给定的字符串中移动:
现在启动条件如下:
"ab98kk7\0" // for better illustration, I explicitly show the terminating 0 character...
//^ str pointing to here
您现在在 while 循环中搜索第一个数字:
"ab98kk7\0"
// ^ str pointing to here after first assignment
这是你的字符串向左移动后的样子:
"ab8kk7\0\0"
// ^ str STILL pointing to here
// notice the duplicate \0 at the end...
循环中的下一个赋值不会修改 str,因为第一个字母,从指针的角度来看,已经是一个数字,所以没有改变,但删除后,情况如下:
"abkk7\0\0\0"
// ^ str STILL pointing to here
查找下一个数字(while 中的赋值):
"abkk7\0\0\0"
// ^ str NOW pointing to here
好吧,让我们跳过最后一个数字的删除...因为之后没有更多的数字,NULL 将分配给 str 并且我们离开循环...
如果换成没有赋值的while循环,只要找到新的数字,就会删除整个字符串:
"ab98kk7\0"
// ^ str pointing to here after first assignment
//^ still pointing to here without assignment!!! (as long as still any digits contained in the string)
对于我在末尾添加数字的示例,您将完全清除字符串...
第二个问题很简短:你完全正确...
但是,此算法效率极低,因为每次删除一个字符时都需要复制整个字符串的其余部分。如果你使用两个指针,你可以做得更好:
void eliminateDigits(char* str)
{
for(char* s = str; *s; ++s)
{
if(!isdigit((unsigned char)*s))
*str++ = *s;
}
*str = 0;
}
附录 – 回应您的评论:
了解指针的性质并将它们传递给函数可能有助于理解问题:
实际上,指针只不过是一个内存地址——存储在特定数量的字节中(多少取决于你编写代码的架构——在现代 64 位硬件上,这通常是八个字节,旧的 32位硬件只使用了其中的四个)。如果您传递一个指向函数的指针,您实际上是将该地址复制到堆栈上,进入该函数的帧中。
让我们想象一下现在的堆栈:
- return value of main (place holder!)
- argv (assuming cdecl calling convention -> arguments placed in reverse order)
- argc
- main's cstr, array of 200 bytes
- main's format, array of 16 bytes
调用 delete_digits:
- return value of main (place holder!)
- argv
- argc
- main's cstr, array of 200 bytes
- main's format, array of 16 bytes
- return value of delete_digits (place holder!)
- delete_digits' cstr, pointer to main's cstr, 8 bytes
在 find_digit 中,您可以简单地将以下几行添加到上面:
- return value of find_digit (place holder!)
- find_digit's cstr, copy of delete_digits' pointer, thus pointing to main's cstr, too
情况如下:
ab98k\0 (main's array)
^ (pointer of delete_digits)
^ (pointer of find_digit)
find_digit(反复)修改自己的指针变体:
ab98k\0 (main's array)
^ (pointer of delete_digits)
^ (pointer of find_digit before returning)
没有赋值,栈上的最后一个指针只是被移除(简单的移除上面最后一行)!只有当您赋值时,delete_digits 的指针也会被调整:
ab98k\0 (main's array)
^ (pointer of delete_digits)
同样适用于 move_left:
ab98k\0 (main's array)
^ (pointer of delete_digits)
^ (pointer of move_left)
move_left 使指针前进 - 通过取消引用它,它访问指针指向的地址 – 这是 main(!) 的数组:
ab88k\0 (main's array)
^ (pointer of delete_digits)
^ (pointer of move_left)
ab8kk\0 (main's array)
^ (pointer of delete_digits)
^ (pointer of move_left)
ab8k\0\0 (main's array)
^ (pointer of delete_digits)
^ (pointer of move_left before returning)
请注意,这里根本没有触及 delete_digits 的指针(在 find_digit 修改其版本时也没有触及...)。
关于c - 从文本中删除数字的程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44287698/