c - 从文本中删除数字的程序

标签 c pointers

这是删除文本中数字的程序。例如 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/

相关文章:

c++ - 循环#includes 是如何解决的?

c - Malloc 使先前分配的指针无效?

c++ - 我不明白数组名称是如何指向数组的指针

c - 在 C 中排序链表的问题

pointers - 如何在Golang中使用反射包删除 slice 中的所有元素?

objective-c - 将 NSURL ** 转换为 CFURLRef *

c - 在二维数组中显示随机数

c - DAC信号发生器stm32

c - C 代码混淆教程

将数组整数值与移位值进行比较