make program to delete all number in text

Pages: 12
i want to make program using pointer that delete all number from text, for example when the input from keyboard is "ab1c9" then the program result "abc" only. so i actually think about using the pointer and overwrite it using the word without number result but it didntesnt seem work :/ and im still confuse about when should i use * or not

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

 
 #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;
   }
 


i tried to make two pointers that point to the same start of the array, but basically to make result not overlap,the first pointer function is where all digits were removed and looking for digit, while the second one showing the result? i still confuse about the purpose of second pointer.

scanf("%s",&str);
should i use & or not?
should i use & or not?

No, since str is a string you don't need the ampersand since the name of the variable (str) works as a pointer.

i still confuse about the purpose of second pointer.

The second pointer appears to be storing the starting location of the string so that you can always go back to the beginning of the array.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#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) ;
    }
}
Easier to use an index instead of pointer.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
  Removes all digits from input and stores the remaining chars in output.
  It's assumed that output is long enough to hold the 
  non-digits + terminating zero
*/
void remove_digits(const char *input, char *output)
{
  size_t len = strlen(input), count = 0;
  for (size_t i = 0; i < len; i++)
  {
    if (!isdigit(input[i]))
    {
      output[count] = input[i];
      count++;
    }
  }
  output[count] = '\0';
}
@devinamuljonox

Fun exercise.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <string>

int main()
{
	std::string text;
	int len;

	std::cout << "Enter a line of text, with numbers in it." << std::endl;
	std::getline(std::cin,text);
	len = text.length(); // Get entered text length
	for(int x=0;x<len;x++)
	{
		if(text[x]>='0' && text[x]<='9')
		{
			for(int a=x;a<len;a++)
				text[a]=text[a+1]; //Shift text left, to remove found number
			x--;// Move back 1 space on entered text, in case there is more than 1 number
		}
	}
	std::cout << "Finished processing the entered text." << std::endl;
        std::cout << "What's left, is : " << text << std::endl << std::endl;
	return 0;
}
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <cctype>
using namespace std;

void noNumbers( char *s )
{
   char *p = s, *q = s;
   while( *p )
   {
      if ( !isdigit( *p ) ) { *q = *p; q++; }
      p++;
   }
   *q = '\0';
}


int main()
{
   const int SIZE = 101;
   char text[SIZE];
   cout << "Enter some text: ";
   cin.getline( text, SIZE - 1 );
   noNumbers( text );
   cout << "De-numbered text is " << text;
}
@jlb thankyou for answering my questions! basically the function of second pointer is just to show the change that i made in the first pointer(?) because its always point the first element of the array(?)

@thomas1965 thanks! yeah i learn about pointer right now so thats why i used pointer

@JLBorges i observed your code, basically when there is a number you delete the number by moving to left(?)
the main part, "sprintf( format, "%%%ds", SZ-1 ) ; // ie. "%199s" if SZ == 200"
dont understand why you need two array here? you make array of format [16] then put the SZ to format(?)
if( scanf( format, cstr ) and this if input not more than array?
sorry still beginner >< havent learnt much about clibrary

@lastchance @whitenite1 thankyou! im learning c now so i dont quite familiar with c++ ><
> basically when there is a number you delete the number by moving to left(?)

Yes.

-----------------------------------------
| a | b | c | d | 8 | e | f | g | h |\0 | 
-----------------------------------------
                  ^ 
                  |
                 cstr 

after move_left(cstr) becomes
----------------------------------------
| a | b | c | d | e | f | g | h |\0 |\0 | 
----------------------------------------



> dont understand why you need two array here?
> you make array of format [16] then put the SZ to format(?)

The idea is this; if we write:
1
2
char cstr[200] ;
scanf( "%199s", cstr );

and later we want to change the size of the array from 200 to, say, 250, we would have to modify the code at two different places, and the onus on doing this correctly would be on us.
1
2
3
4
// char cstr[200] ;
char cstr[250] ; // **** modify size
// scanf( "%199s", cstr );
scanf( "%249s", cstr ); // **** also modify the format string 



With
1
2
3
4
5
6
7
8
9
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

scanf( format, cstr ) ;

We can change SZ whenever we please; maintaining the correct field width for scanf is automatic.
1
2
3
4
5
6
7
8
9
10
// enum { SZ = 200 } ;
enum { SZ = 250 } ; // **** modify size, in just this one place

char cstr[SZ] ;

// prepare format string to read at most SZ-1 characters
char format[16] ;
sprintf( format, "%%%ds", SZ-1 ) ; // ie. "%249s" if SZ == 250

scanf( format, cstr ) ;


C is a more difficult language to program in, in comparison to C++.
It is laughable that the Linux crowd hasn't yet realised this; with blinkered eyes, one misses a lot of obvious things.
@JLBorges thankyou!! can i ask about our program, kinda lost to follow the path

for example i put 'ab98k' after the delete digit and find digit function, it will return pointer if there is digit then the pointer will be passed to move_left, there will be '98k' only at this point
then in move left function
{ while( ( *cstr = *(cstr+1) ) ) ++cstr ; }
this will make '88k'? then ++cstr -> 8k(?) and this will left the 8 still there(?)
and after this will come back again to delete digit function or find digit?
and the find digit function control every time there is a digit or just for the first time occurence?
thankyou!!
You have in array (I'll use '.' for NULL.)
ab98k.

The find_digit() returns pointer to 9:
ab98k.
  ^

That is where the move_left starts from.
On the first iteration the condition copies the 8 and then moves the pointer:
ab88k.
   ^

On the second iteration the condition copies the k and then moves the pointer:
ab8kk.
    ^

On the third iteration the condition copies the NULL and loop ends.:
ab8k..
    ^


The pointer that did move in move_left() is a local variable and has no effect on delete_digits().
Before the next call to find_digit(), the pointer is still at the third char:
ab8k..
  ^

As that position has a digit, the find_digit() returns same address, and that is what the move_left() is called with.
@keskiverto @JLBorges
i understood!!!!!!!!!!!!!!!! thankyou so much!!!!!!!!!you save me from confusion ><

but i still have question

1
2
void delete_digits( char* cstr ) // remove decimal digits
{ while( ( cstr = find_digit(cstr) ) ) move_left(cstr) ; }


in this function
"cstr=find digit(cstr)"
cstr in bold is a pointer?

i didnt understand why you have to store the find_digit result which pointer to the number digit to the pointer cstr again?
1
2
ab98k.
  ^


what is the purpose ?
is this mean the pointer cstr(right) result from find digit was given to pointer cstr (left) to replace the pointer that was passed from the calling function in main?
and when i change to { while( ( find_digit(cstr) ) ) move_left(cstr) ; }
the program seems error

1
2
3
4
5
6
7
char* find_digit(char* cstr)
{
	for (; *cstr; ++cstr)
		if (isdigit(*cstr))
			return cstr;
	return NULL; // not found
}

and at the end of this function or when there is no digit, it will return NULL for last word 'k' in 'ab98k' right? it will return null to the while in delete_digit function that will terminate it and return to main?
so the NULL function is to terminate for loop?
\

Last edited on
> cstr in bold is a pointer?

Yes. It is the pointer passed to the function void delete_digits( char* cstr )


> why you have to store the find_digit result which pointer to the number digit to the pointer cstr again?

The pointer passed to char* find_digit( char* cstr ) is a copy; the modification made to the copy of the pointer in the function (make it point to the first occurrence of a decimal digit) would not be visible in the calling function. It returns the modified pointer (pointer to the first digit); we want to call move_left() with (a copy of) the pointer returned by char* find_digit()


> when there is no digit, it will return NULL for last word 'k' in 'ab98k' right?
> it will return null to the while in delete_digit function that will terminate it

Yes. A return value of NULL indicates that there are no more digits to be found; and the loop is exited when he pointer becomes NULL

Note that the modifications that we have made to the pointer in delete_digits() will not be visible to main(); what the function gets is a copy; and what it modifies is the copy that it got.
@JLBorges thankyou for replying !!!!!!!!!!!!!

the left cstr is the pointer passed to the function void delete_digits from main.

while( ( cstr = find_digit(cstr) )

is this mean the pointer cstr(right) which is result from find digit was given to pointer cstr (left) to replace the pointer that was passed from the calling function in main?


And when I change to
{ while( ( find_digit(cstr) ) ) move_left(cstr) ; }
the program seems to error

when i debug it, it removes first character (not the one found) from the string if find_digit(cstr) is != NULL
why it removes first character? and not the produce result from find_digit function?


why is this happen?
what is the difference between
{ while( (cstr= find_digit(cstr) ) ) move_left(cstr) ; }
and
{ while( ( find_digit(cstr) ) ) move_left(cstr) ; }

Last edited on
while( (cstr= find_digit(cstr) ) ) move_left(cstr) ;
is same as
1
2
3
4
while( (cstr = find_digit(cstr) ) )
{
  move_left(cstr) ;
}

and achieves same as
1
2
3
4
5
6
7
char * pdigit = find_digit(cstr);
while( pdigit )
{
  cstr = pdigit;
  move_left(cstr);
  pdigit = find_digit(cstr);
}


Meanwhile, in
1
2
3
4
while( find_digit(cstr) ) // this does not change cstr
{
  move_left(cstr); // this does not change cstr
}
One more variation. This is nearly identical to Thomas1965's. To me, it's easiest to code these by thinking in terms of a source pointer and a destination pointer:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <stdlib.h>
#include <cctype>

void
deldigit(char *str)
{
    char *dst = str;
    for (char *src = str; *src; ++src) {
	if (!isdigit(*src)) {
	    *dst++ = *src;
	}
    }
    *dst = 0;			// null-terminate it
}

Note that the solutions that shift characters to the left run in O(n2) time whereas the ones that copy single characters run in O(n) time.
You should & in order to refer what's in the pointer and if you want to delete what the pointer points to, you should delete it without the &. Make sure you work slowly with pointers as things can get complicated and you can find yourself dealing with a lot of errors.
of course, these error can be detected with programs such as checkmarx and others but it's also recommended to do it on your own.
Good luck, Ben.
@keskiverto

i really want to know how is the pointer work here:
assume ab98k

1
2
3
4
while( (cstr= find_digit(cstr) ) ) 
{
move_left(cstr) ;
}


find digit(cstr) will give 98k
this function will do loop until all '98k' is substituted to cstr(cstr is a pointer to
to ab98k,passed from main), thats why cstr in local variable will point to '98k'
is my assumption true?

1
2
3
4
5
while( (cstr = find_digit(cstr) ) ) /*this will do loop until all '98k' was assign to cstr*/
{
  move_left(cstr) ;
}

and achieves same as

1
2
3
4
5
6
7
char * pdigit = find_digit(cstr); /* put '98k' to pointer pdigit, so both pointer point number 9 */
while( pdigit ) /*will looping as long as !=NULL 、9->8->k*/
{
  cstr = pdigit; /*will assign pdigit to cstr */
  move_left(cstr);   /*pass '98k' to move=left, result is '8k'*/
  pdigit = find_digit(cstr);    /*pass '8k' to pdigit, then enter the loop while again
} */

i tried understand this, is my assumption true?

Meanwhile, in


while( find_digit(cstr) ) // this does not change cstr ---> can you explain more??? find_digit (cstr) will return '98k' and will do loop as long as !=NULL
1
2
{
  move_left(cstr); // this does not change cstr  
->because pointer cstr in local variable point to 'a' in 'ab98k' -> thats why the program will result 'k' only in the end..true???
}[/code]
Last edited on
@dhayden you delete digit by moving the non number to another pointer, i know that your code really much better and simple!!!, but i wonder is there algorithm behind that?
the first iteration will
*dst++ = *src;
assign pointer src to dst
then increment dst by 1
then after that ++src in for loop... , is ++src and src++ result same in this for loop?
i know that if i change to ++dst will result error

@benhart yes >< pointer is too complicated, if i dont understand when should i use & and * will result in lots of error.
Last edited on
find digit(cstr) will give 98k

No, not quite. The function returns a pointer.

Before the loop there exist an array: { 'a', 'b', '9', '8', 'k', '\0' } and the pointer cstr points to the first element of array (that contains the a).

When you do call find_digit(cstr) the first time, it returns a pointer that points to the third element of the array (that contains the 9). The pointer points to somewhere other than memory address NULL.

Address NULL converts to false in condition and loop ends. Other than NULL converts to true and loop evaluates its body.

1
2
3
4
5
6
7
// cstr points to first element
while( find_digit(cstr) )
{
// cstr still points to first element
  move_left(cstr);
// cstr still points to first element
}

On first iteration the condition is true and the move_left() executes.
The array after iteration: { 'b', '9', '8', 'k', '\0', '\0' }
On second iteration the condition is still true and the move_left() executes.
The array after iteration: { '9', '8', 'k', '\0', '\0', '\0' }
On 3rd iteration the condition is still true and the move_left() executes.
The array after iteration: { '8', 'k', '\0', '\0', '\0', '\0' }
On 4th iteration the condition is still true and the move_left() executes.
The array after iteration: { 'k', '\0', '\0', '\0', '\0', '\0' }
On 5th iteration the condition is false, the move_left() will not execute, and loop ends.
Array after loop: { 'k', '\0', '\0', '\0', '\0', '\0' }


1
2
3
4
*dst++ = *src;
// is same as
*dst = *src;
++dst;

vs.
1
2
3
4
*(++dst) = *src;
// is same as
++dst;
*dst = *src;


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    char *dst = str;
    for (char *src = str; *src; ++src) {
	if (!isdigit(*src)) {
	    *dst++ = *src;
	}
    }
// is equivalent to
    char *dst = str;
    char *src = str;
    while ( *src ) {
	if (!isdigit(*src)) {
	    *dst++ = *src;
	}
        ++src;
    }
I think that, "under the hood", remove_if does the same source-destination pointer manoeuvres as outlined above.

However, could someone possibly explain to me why I can't simply write
char *p = remove_if( s, s + strlen( s ), isdigit );
in the code below, rather than having to write a separate predicate (or, as here, lambda function).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <algorithm>
#include <cctype>
#include <cstring>
using namespace std;

//======================================================================

void noNumbers( char *s )
{
   char *p = remove_if( s, s + strlen( s ), []( char c ){ return isdigit( c ); } );
   *p = '\0';
}

//======================================================================

int main()
{
   const int SIZE = 101;
   char text[SIZE];
   cout << "Enter some text: ";
   cin.getline( text, SIZE - 1 );
   noNumbers( text );
   cout << "De-numbered text is " << text;
}
Pages: 12