struggling with strings

T

tuchka

Hi guys!
I am trying to learn C programming but my java background blocks my
brains.
I have a book with a lot of functions and some of them don't work
correctly, so I have opportunity to exercise in C by correction
(strange, huh?).
For example, i want to write function that removes all occurences of
given substring from string.
I have two functions so far:

1. removes first substring from the string (i made it after
corrections of the function that i had in the horrible book:

char *strstr_rem_first(char *string, char *substring) {

int i, j, k, loc=-1;

for(i=0; string && (loc==-1); i++) {
for(j=i, k=0; string[j] ==substring[k];j++, k++)
if(!substring[k+1])
loc=i;
if(loc != -1) { //substring was found
for(k=0; substring[k];k++); {
for(j=loc, i=loc+k; string; j++, i++) {
string[j] = string;
string='\0';
}
}
}
}
return (string);
}
2. finds rightmost index of the substring (returns -1 if not found):

int substring_index(const char *string, const char *substring) {

int i, j, k;
for(i=0; string;i++)
for(j=i,k=0; string[j] == substring[k]; j++, k++)
if(!substring[k+1])
return(i);

return(-1);
}

Now, armed with these I wanted to construct function that removes all
substrings.

I though about somthing like this:

while(substring_index() > 0)
string_original becomes substring_rem_first

return string_original

Unfortunately, because strings are treated as arrays and i can't
transfer references as easily as i got used to, i can't figure out how
to accomplish it in C.
I shuffled some pointers and some strcpy() etc in vain.
Especially this 'string_original becomes substring_rem_first' bothers
me.
I always end up with 'undefined' reference to 'substring_rem_first'.

Could you help me out? :)
 
E

Ekkehard Morgenstern

Hi tuchka,

tuchka said:
1. removes first substring from the string (i made it after
corrections of the function that i had in the horrible book:
2. finds rightmost index of the substring (returns -1 if not found):

Check out the functions declared in "string.h". :)

Here's a function to remove all occurrences of "substring" from "string":

#include <string.h>

char* strstr_rem_all( char* string, const char* substring ) {
char* occurrence; int substr_len = strlen( substring ); int move_len =
strlen( string ) - substr_len + 1; /* +1 b/c of terminating '\0' */
while ( occurrence = strstr( string, substring ) ) {
memmove( occurrence, string + substr_len, move_len );
}
return string;
}

memmove() is used instead of memcpy(), because it handles overlapping
copies. :)

I hope that helps! :)

Regards,
Ekkehard Morgenstern.
 
T

tuchka

Thank you, Ekkehard,
I see how that function could've work but i still cannot get it to
work.
The function as written by you gives the following error:

C:\Sveta\C_PROG~1\STRING~1>str_test
123fart456fart789fart

Reverse traf987traf654traf321 is traf987traf654traf321
Filled with x became xxxxxxxxxxxxxxxxxxxxx
After removing first fart became 123456fart789fart
After removing all fart became
123art456rt456rt456rt456rt456rt456rt456rt?

Exiting due to signal SIGSEGV
General Protection Fault at eip=0000772e
eax=00000000 ebx=00000000 ecx=ffffffff edx=ffffffff esi=ffffffff
edi=ffffffff
ebp=00090390 esp=0008ef6c
program=C:\SVETA\C_PROG~1\STRING~1\STR_TEST.EXE
cs: sel=01a7 base=029a0000 limit=0009ffff
ds: sel=01af base=029a0000 limit=0009ffff
es: sel=01af base=029a0000 limit=0009ffff
fs: sel=017f base=00005a50 limit=0000ffff
gs: sel=01bf base=00000000 limit=0010ffff
ss: sel=01af base=029a0000 limit=0009ffff
App stack: [00090560..00010560] Exceptn stack: [000104c0..0000e580]

Call frame traceback EIPs:
0x0000772e
0x00003946
0x00001b82
0x000033d8

I re-wrote it like this but again i've got 'undefined reference' for
str_rem_first(string,substring):

char *strstr_rem_all(char *string, const char *substring) {
//char occurence[strlen(string)];
char *ptr;
int substr_len=strlen(substring);
int move_len=strlen(string)-substr_len+1;

while(ptr=strstr(string, substring)) {
char occurence[strlen(string)];
memmove(occurence, str_rem_first(string,substring),
strlen(string)-substr_len+1);
}
return string;
}

Sigh, sigh :-(
Why the lang. is so hard?
 
A

Anupam

Ekkehard Morgenstern said:
Hi tuchka,



Check out the functions declared in "string.h". :)

Here's a function to remove all occurrences of "substring" from "string":

#include <string.h>

char* strstr_rem_all( char* string, const char* substring ) {
char* occurrence; int substr_len = strlen( substring ); int move_len =
strlen( string ) - substr_len + 1; /* +1 b/c of terminating '\0' */
while ( occurrence = strstr( string, substring ) ) {
memmove( occurrence, string + substr_len, move_len );
}
return string;
}

memmove() is used instead of memcpy(), because it handles overlapping
copies. :)

Isn't there something a bit weird here.
Be careful abt how much you are moving ... the length of the initial
string - that of the substring +1 . This does not change inside the
loop but each time the string gets shorter.

What about this ? It should work.

char* strstr_rem_all( char* string, const char* substring ) {
char* occurrence;
int substr_len = strlen( substring );
int move_len;
while ( occurrence = strstr( string, substring ) ) {
move_len = strlen( occurrence ) - substr_len + 1;
memmove( occurrence, occurrence + substr_len, move_len );
}
return string;
}
 
E

Ekkehard Morgenstern

Hi tuchka,

I didn't test my code before posting it, because I assumed you'd be having
some thought about it before using it, but yeah, there's an obvious bug in
it:


Instead of "memmove( occurrence, string + substr_len, move_len )", it should
read "memmove( occurrence, occurrence + substr_len, move_len )", of course.
:)

Regards,
Ekkehard Morgenstern.
 
E

Ekkehard Morgenstern

Hi tuchka,

Sorry this didn't work either. ;-)

Ekkehard Morgenstern said:
Instead of "memmove( occurrence, string + substr_len, move_len )", it should
read "memmove( occurrence, occurrence + substr_len, move_len )", of
course.

Anupam was right, I moved too much.

Here's a complete test program that works:

#include <stdio.h>
#include <string.h>

char* strstr_rem_all( char* string, const char* substring ) {
char* occurrence; int substr_len = strlen( substring );
while ( occurrence = strstr( string, substring ) ) {
int move_len = strlen( occurrence ) - substr_len + 1; /*
+1 b/c of terminating '\0' */
memmove( occurrence, occurrence + substr_len, move_len );
}
return string;
}

int main( int argc, char** argv ) {
if ( argc >= 3 ) {
printf( "string = '%s', substr = '%s'\n", argv[1],
argv[2] );
strstr_rem_all( argv[1], argv[2] );
printf( "result = '%s'\n", argv[1] );
}
return 0;
}

Notice that the first argument in strstr_rem_all() must point to modifyable
memory, like a string buffer like argv[1]. If you let it point to a constant
(string literal), you will get an access violation error.

I hope this helped! :)

Regards,
Ekkehard Morgenstern.
 
E

Ekkehard Morgenstern

Hi Anupam,

Anupam said:
char* strstr_rem_all( char* string, const char* substring ) {
char* occurrence;
int substr_len = strlen( substring );
int move_len;
while ( occurrence = strstr( string, substring ) ) {
move_len = strlen( occurrence ) - substr_len + 1;
memmove( occurrence, occurrence + substr_len, move_len );
}
return string;
}

Yup, you're right! :)

I didn't test the code beforehand, and it was late! I posted a complete test
program now for tuchka in the other branch of the message tree. :)

Coincidentially we have the same solution, I guess there's not many ways to
do it right! ;-)

Regards,
Ekkehard Morgenstern.
 
T

tuchka

Thank you very much Ekkehard and Anupam! It works!
I see that I need to get better book. When I tried to re-write
'memmove'
function (i looked it up in internet) for some reason i did not notice
that type of
arguments were 'void'. I thought it arrays. 'void' does not make much
sense to me. I am lacking
essential information, i see that much. One last small question.

When i place the function directly into the program and call it from
'main' it works like a charm,
but when i put it into 'library' file (that is with asossiated header
file) and call it from test
program it gives the following:

////////////////////////////////////////////////////

After removing first fart became 123456fart678fart
After removing all fart became 123456678
Exiting due to signal SIGSEGV
General Protection Fault at eip=0000767e
eax=00000000 ebx=00000000 ecx=ffffffff edx=ffffffff esi=ffffffff
edi=ffffffff
ebp=00090390 esp=0008ef6c
program=C:\SVETA\C_PROG~1\STRING~1\STR_TEST.EXE
cs: sel=01a7 base=029a0000 limit=0009ffff
ds: sel=01af base=029a0000 limit=0009ffff
es: sel=01af base=029a0000 limit=0009ffff
fs: sel=017f base=00005a50 limit=0000ffff
gs: sel=01bf base=00000000 limit=0010ffff
ss: sel=01af base=029a0000 limit=0009ffff
App stack: [00090560..00010560] Exceptn stack: [000104c0..0000e580]

Call frame traceback EIPs:
0x0000767e
0x00003896
0x00001942
0x000033d8
////////////////////////////////////////////////////

I'm using gcc compiler and link like this:
gcc -c -g strutil.c

gcc -c -g str_test.c

gcc -o str_test.exe str_test.o strutil.o


What it can be? Maybe my compiler or my computer?
Do you have any ideas?

Thanks once again for your help. I'm going for a new book right away.
:)
 
E

Ekkehard Morgenstern

Hi tuchka,

tuchka said:
When i place the function directly into the program and call it from
'main' it works like a charm,
but when i put it into 'library' file (that is with asossiated header
file) and call it from test
program it gives the following:

I don't know what you're doing, but it could be that you used a string
literal for both parameters like:

strstr_rem_all( "123123abc123abc", "abc" );

This will cause an access violation, since the function assumes that the
first parameter is a buffer, not a constant.

It will be better to declare the function such that it returns no pointer.
This way you'll have to provide a buffer to get the result:

void strstr_rem_all( char* string, const char* substring ) {
char* occurrence; int substr_len = strlen( substring );
while ( occurrence = strstr( string, substring ) ) {
int move_len = strlen( occurrence ) - substr_len + 1; /* +1 b/c
of terminating '\0' */
memmove( occurrence, occurrence + substr_len, move_len );
}
}

btw, the "void*" in memmove() and memcpy() mean that these parameters can be
assigned any pointer value. Note that "void" is not the same as "void*". :)

I hope this helps.

Regards,
Ekkehard Morgenstern.
 
T

tuchka

Thank you, Ekkehard,
i see that i need to read regular text book not a 'bible' that i have,
to understand many concepts clearly. All my troubles are originating
from the fact that i don't know what i'm doing :) I just bought two
books for beginners and going to study it.
Your input was most helpful.

Cheers,
tuchka
 
A

Anupam

Thank you very much Ekkehard and Anupam! It works!
I see that I need to get better book. When I tried to re-write
'memmove'
function (i looked it up in internet) for some reason i did not notice
that type of
arguments were 'void'. I thought it arrays. 'void' does not make much
sense to me. I am lacking
essential information, i see that much. One last small question.

When i place the function directly into the program and call it from
'main' it works like a charm,
but when i put it into 'library' file (that is with asossiated header
file) and call it from test
program it gives the following:

////////////////////////////////////////////////////

After removing first fart became 123456fart678fart
After removing all fart became 123456678
Exiting due to signal SIGSEGV
General Protection Fault at eip=0000767e
eax=00000000 ebx=00000000 ecx=ffffffff edx=ffffffff esi=ffffffff
edi=ffffffff
ebp=00090390 esp=0008ef6c
program=C:\SVETA\C_PROG~1\STRING~1\STR_TEST.EXE
cs: sel=01a7 base=029a0000 limit=0009ffff
ds: sel=01af base=029a0000 limit=0009ffff
es: sel=01af base=029a0000 limit=0009ffff
fs: sel=017f base=00005a50 limit=0000ffff
gs: sel=01bf base=00000000 limit=0010ffff
ss: sel=01af base=029a0000 limit=0009ffff
App stack: [00090560..00010560] Exceptn stack: [000104c0..0000e580]

Call frame traceback EIPs:
0x0000767e
0x00003896
0x00001942
0x000033d8
////////////////////////////////////////////////////

I'm using gcc compiler and link like this:
gcc -c -g strutil.c

gcc -c -g str_test.c

gcc -o str_test.exe str_test.o strutil.o


What it can be? Maybe my compiler or my computer?

There is *always* only one problem and that's incorrect coding. It is
tempting to think that we have discovered a major bug... :) but in
99.967% (there's a nice signature floating around to corroborate this)
of the cases, the fault lies with us.

Interesting . Could you give us the code for both the files. It would
be helpful if we had solid code at hand. I would not like to comment
before seeing that.
Do you have any ideas?

Thanks once again for your help. I'm going for a new book right away.
:)

Glad to be of help. Please do use the services of this newsgroup
for clearing up your doubts. I would also like to suggest that you
could try using the Turbo C IDE. I had grown up with it and have
always loved the excellent help system. It is very simple , not hi-fi
, but it gives one a beautiful test bed to program. Of course I was
initially trapped into thinking that it was C and only later realised
that C is much bigger. No doubt there'll be many people with wider
experience who can suggest better ones. As far as books go I'll just
keep mum. I have learnt that it can be very dicey to suggest a book...
;) It is a matter of much sensitivity. K&R would be recommended though
at least at some point in the learning curve.

Regards,
Anupam
 
T

tuchka

Hi Anupam:
Please take a look at my files. I wonder if you find the cause of this
exception. It would be very interesting. I checked once again
everything (i even found out that i forgot to include strstr_rem_all()
into header!) but the message still appears after execution of
str_test.exe that i am getting by the following commands:
C:\C_PROG~1\STRING~1>gcc -c -g strutil.c

C:\C_PROG~1\STRING~1>gcc -c -g str_test.c

C:\C_PROG~1\STRING~1>gcc -o str_test.exe str_test.o strutil.o

C:\C_PROG~1\STRING~1>str_test
123fart456fart789fart

The following are my files:
--------------------------------------------------------
str_test2.c (as you guys suggested is working very well)
--------------------------------------------------------

#include <stdio.h>
#include <string.h>

char* strstr_rem_all( char* string, const char* substring ) {
char* occurrence; int substr_len = strlen( substring );
while ( occurrence = strstr( string, substring ) ) {
int move_len = strlen( occurrence ) - substr_len + 1;
/*
+1 b/c of terminating '\0' */
memmove( occurrence, occurrence + substr_len, move_len
);
}
return string;
}

int main( int argc, char** argv ) {
if ( argc >= 3 ) {
printf( "string = '%s', substr = '%s'\n", argv[1],
argv[2] );
strstr_rem_all( argv[1], argv[2] );
printf( "result = '%s'\n", argv[1] );
}
return 0;
}
------------------------------------------------------------------------
strutil.h (i am making to create my library)
----------------------------------------------------------------------
/*strutil.h*/

extern char *strrev(char *string); //return reversed string
extern char *strset(char *string, int letter);
extern char *strstr_rem_first(char *string, char *substring);
extern int substring_index(const char *string, const char *substring);
extern char *strstr_rem_all( char *string, const char *substring );
-----------------------------------------------------------------------
strutil.c (contains my functions)
-----------------------------------------------------------------------
#include <string.h>
#include "strutil.h"

//reverse
char *strrev(char *string) {
char *backward = string;
char *forward = string;
char temp;
//set 'backward' to the null byte terminating the string
while(*backward){
backward++;
}
while(forward<backward) {
--backward;
temp=*backward;
*backward=*forward;
*forward=temp;
++forward;
}
return (string);
}
//setting to char
char *strset(char *string, int letter) {
char *original=string;

while(*string) {
*string++ = letter;
}
return (original);
}
//finds rightmost index of substr
int substring_index(const char *string, const char *substring) {
int i, j, k;

for(i=0; string;i++)
for(j=i,k=0; string[j] == substring[k]; j++, k++)
if(!substring[k+1])
return(i);
return(-1);
}
//removes first sbstr
char *strstr_rem_first(char *string, char *substring) {
int i, j, k, loc=-1;

for(i=0; string && (loc==-1); i++) {
for(j=i, k=0; string[j] ==substring[k];j++, k++)
if(!substring[k+1])
loc=i;
if(loc != -1) { //substring was found
for(k=0; substring[k];k++); {
for(j=loc, i=loc+k; string; j++, i++) {
string[j] = string;
string='\0';
}
}
}
}
return (string);
}
//removes all substr
char *strstr_rem_all( char *string, const char *substring ) {
char *occurrence; int substr_len = strlen( substring );
while (occurrence = strstr( string, substring ) ) {
int move_len = strlen( occurrence ) - substr_len + 1;
memmove( occurrence, occurrence + substr_len, move_len
);
}
return string;
}
-----------------------------------------------------------------------
str_test.c (which after compiling and linking with strutil.c gives the
above message)
-------------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include "strutil.h"

int main() {

char *str_ptr;
char *substr_ptr;

char letter ='x';
char s[100];
char s_cache1[100];
char s_cache2[100];
char substr[5];

gets(s);

str_ptr=s;
strcpy(substr, "fart");

strcpy(s_cache1, s);
strcpy(s_cache2, s);

printf("\nReverse %s is %s", strdup(s), strrev(s));

printf("\nFilled with %c became %s", letter, strset(s, letter));

printf("\nAfter removing first %s became %s", substr,
strstr_rem_first(s_cache1, "fart"));
printf("\nAfter removing all %s became %s", substr,
strstr_rem_all(s_cache2, "fart"));

printf("\nIndex of first substring in %s is %d",
substring_index("hello", "fart"));

return 0;

}
 
A

Anupam

Hi Anupam:
Please take a look at my files. I wonder if you find the cause of this
exception. It would be very interesting. I checked once again
everything (i even found out that i forgot to include strstr_rem_all()
into header!) but the message still appears after execution of
str_test.exe that i am getting by the following commands:
C:\C_PROG~1\STRING~1>gcc -c -g strutil.c

C:\C_PROG~1\STRING~1>gcc -c -g str_test.c

C:\C_PROG~1\STRING~1>gcc -o str_test.exe str_test.o strutil.o

C:\C_PROG~1\STRING~1>str_test
123fart456fart789fart


Wow didn't you supply the command line parameters here? This I cant
get. And still it is outputting stuff. Check it once . Maybe
something's wrong in what u gave us.
The following are my files:

?? str_test.c I think from the compilation. Is this the code u
compiled?

int main( int argc, char** argv ) {
if ( argc >= 3 ) {
printf( "string = '%s', substr = '%s'\n", argv[1],
argv[2] );
strstr_rem_all( argv[1], argv[2] );
printf( "result = '%s'\n", argv[1] );
}
return 0;

Consider return EXIT_SUCCESS (or FAILURE) by including stdlib.h
}
------------------------------------------------------------------------
strutil.h (i am making to create my library)
----------------------------------------------------------------------
/*strutil.h*/

extern char *strrev(char *string); //return reversed string
extern char *strset(char *string, int letter);

Whoa, check out your names, they are common to functions in string.h
which also u r including.
extern char *strstr_rem_first(char *string, char *substring);
extern int substring_index(const char *string, const char *substring);
extern char *strstr_rem_all( char *string, const char *substring );
-----------------------------------------------------------------------
strutil.c (contains my functions)
-----------------------------------------------------------------------
#include <string.h>
#include "strutil.h"

//reverse
char *strrev(char *string) {
char *backward = string;
char *forward = string;
char temp;
//set 'backward' to the null byte terminating the string
while(*backward){
backward++;
}
while(forward<backward) {
--backward;
temp=*backward;
*backward=*forward;
*forward=temp;
++forward;
}
return (string);
}

Compiler is thinking : Is this the real strrev or is the one in the
standard library the one u want to use? BIG problem.
//setting to char
char *strset(char *string, int letter) {
char *original=string;

while(*string) {
*string++ = letter;
}
return (original);
}
//finds rightmost index of substr
int substring_index(const char *string, const char *substring) {
int i, j, k;

for(i=0; string;i++)
for(j=i,k=0; string[j] == substring[k]; j++, k++)
if(!substring[k+1])
return(i);
return(-1);
}
//removes first sbstr
char *strstr_rem_first(char *string, char *substring) {
int i, j, k, loc=-1;

for(i=0; string && (loc==-1); i++) {
for(j=i, k=0; string[j] ==substring[k];j++, k++)
if(!substring[k+1])
loc=i;
if(loc != -1) { //substring was found
for(k=0; substring[k];k++); {
for(j=loc, i=loc+k; string; j++, i++) {
string[j] = string;
string='\0';
}
}
}
}
return (string);
}
//removes all substr
char *strstr_rem_all( char *string, const char *substring ) {
char *occurrence; int substr_len = strlen( substring );
while (occurrence = strstr( string, substring ) ) {
int move_len = strlen( occurrence ) - substr_len + 1;
memmove( occurrence, occurrence + substr_len, move_len
);
}
return string;
}
-----------------------------------------------------------------------
str_test.c (which after compiling and linking with strutil.c gives the
above message)
-------------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include "strutil.h"

int main() {

char *str_ptr;
char *substr_ptr;

char letter ='x';
char s[100];
char s_cache1[100];
char s_cache2[100];
char substr[5];

gets(s);

Warning ! Warning ! gets is dangerous . Refer to Richard Heathfield'
s page for more info...(The URL was already given earlier)
str_ptr=s;
strcpy(substr, "fart");

strcpy(s_cache1, s);
strcpy(s_cache2, s);

printf("\nReverse %s is %s", strdup(s), strrev(s));

printf("\nFilled with %c became %s", letter, strset(s, letter));

printf("\nAfter removing first %s became %s", substr,
strstr_rem_first(s_cache1, "fart"));
printf("\nAfter removing all %s became %s", substr,
strstr_rem_all(s_cache2, "fart"));

printf("\nIndex of first substring in %s is %d",
substring_index("hello", "fart"));

return 0;

}

Try changing the names of those functions. Your function names are
colliding with the standard ones in the global namespace.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top