程序从文本中删除数字

时间:2017-05-31 14:37:56

标签: 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结果存储到指针cstr

find_digit函数的结果是这个,那为什么还要再次将它存储在指针{ while( ( find_digit(cstr) ) ) move_left(cstr) ; }中?

ab98k。      ^

目的是什么?当我改为char* find_digit(char* cstr) { for (; *cstr; ++cstr) if (isdigit(*cstr)) return cstr; return NULL; // not found } 时,程序似乎出错了。

我的第二个问题:

while

在此函数结束时或没有数字时,它会为'ab98k'中的最后一个单词'k'返回NULL吗?它将返回null到delete_digit函数中的main,它将终止它并返回#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; } ?那么NULL的目的是终止for循环吗?

另一个版本

<p-dropdown [options]="listCustomers_itm" placeholder="Selezionare" [(ngModel)]="Customer_itm" [ngModelOptions]="{standalone: true}" [style]="{'width':'225px'}" filter="filter"  (onChange)="onCustomerSelect($event.value)">
</p-dropdown>

4 个答案:

答案 0 :(得分:2)

第一个问题:如果将数组传递给函数,该函数实际上会收到指向该数组的指针。您现在可以修改此指针(指针本身,而不是指向的值),而根本不修改原始数组。如果你将该指针传递给另一个函数,你实际上传递了该指针的副本,i。即如果修改第二个函数中的新指针,则第一个函数的指针根本不受影响。这很重要(在其他地方),尤其是从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位硬件上,这通常是8个字节,较旧的32个-bit硬件仅使用其中的四个)。如果将指针传递给函数,则实际上将此地址复制到堆栈中,并将其复制到此函数的框架中。

现在让我们想象一下堆栈:

- 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&#39;这里没有触及指针(因为当find_digit修改了它的版本时也没有...)。

答案 1 :(得分:0)

你的

{ while( ( find_digit(cstr) ) ) move_left(cstr) ; }
如果find_digit(cstr)是!= NULL,

从字符串中删除第一个字符(不是找到的字符)

如果添加临时变量

,则更容易理解
char *tmp;
while( ( tmp = find_digit(cstr) ) ) move_left(tmp) ;

但是这个版本在从字符串的开头和原始版本中搜索数字时效果会较差

    while (cstr = find_digit(cstr))
         move_left(cstr);

仅从最后一次发现。

答案 2 :(得分:0)

函数find_digit返回一个指针,该指针将该指针发送到变量cstr,该变量与其自身函数中的cstr无关。每个cstr在其自身的功能中都是独一无二的。

所以基本上如果符号不是数字,它返回NULL并且delete_digit中的while循环停止。

如果你没有在delete_digit函数中指定cstr,程序将会出错,因为在while循环中使用了cstr。

这回答了你的第二个问题。

答案 3 :(得分:0)

你不能......

string removeDigits(const string& str) {

   string noDigits;
    for (int i = 0; i < str.length(); ++i) {
       if(!(isDigit(str[i]))) 
          noDigits += str[i] + ""; 
    }
return noDigits;
}

虽然isDigit是一些辅助函数,它检查char是否为[0-9]