3

A function I created, which I refer to as string_deletion, deletes occurrences of a specific substring and shifts the string leftwards by the length of the substring. The function accepts two parameters: the pointer to the location in the array wherein the first letter of the substring is encountered, and the length of the word.

Here is the function:

void string_deletion(char *s, int m)
{
    char *index=s+m;
    while(*index!=0)
    {
        *(index-m)=*(index++);
    }
    *(index-m)=0;
}

The function shifts all the characters after the substring leftwards by an amount dependent on the length of the substring, which has been denoted by m. I have set the index pointer to point to the character that occurs immediately after the occurrence of the substring, and this is the mark from where the shifting commences. The loop is executed until a NUL character is encountered, after which it exits the loop. At the culmination, the NUL is appended to the end of the string.

Whereas the other parts of the main code work seamlessly, invoking this specific function, as and when necessary, makes the program cease working and it yields an error. What explains this?

Here's the complete code:

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

int string_len(char *s)
{
    int i=0;
    char *m=s;
    while(*m!=0)
    {
        i++;
        m++;
    }
    return i;
}
void word_enter(char *word_search)
{
    char r;
    char *m=word_search;
    while((r=getchar())!=EOF)
    {
        if(r=='\n')
        {
            *m=0;
            break;
        }
        else
        {
            *(m++)=r;
        }
    }
}
 
void string_disp(char *s)
{
    char *d=s;
    while(*d!=0)
    {
        putchar(*(d++));
    }
}

int string_comp(char *s, char *m)
{
    int stringlength_one=string_len(s);
    int stringlength_two=string_len(m);
    char *s_one=s;
    char *s_two=m;
    if(stringlength_one!=stringlength_two)
    {
        return 1;
    }
    else
    {
        while(*s_one!=0)
        {
            if(*s_one!=*s_two)
            {
                return 1;
            }
            s_one++;
            s_two++;
        }
    }
    return 0;
}

void string_deletion(char *s, int m)
{
    char *index=s+m;
    while(*index!=0)
    {
        *(index-m)=*(index++);
    }
    *(index-m)=0;
}

void string_search(char *s,char *d)
{
    char *m=s;
    char word_buffer[20];
    char *buffer_index=word_buffer;
    while(m!=&s[string_len(s)-string_len(d)+1])
    {
        buffer_index=word_buffer;
        if(*m==*d)
        {   
            int i=0;
            char *r=m;
            while(i<=string_len(d) && *r!=0)
            {
                *(buffer_index++)=*(r++);
                i++;
            }
            *buffer_index=0;
            if(string_comp(word_buffer,d)==0)
            {
                printf("\nInvoking deletion sequence\n");
                string_deletion(m,string_len(d));
            }
        }
    m++;
    }
}   
    
int main(void)
{
    int pos;
    char main_string[100],word[20];
    printf("Enter the main string: ");
    word_enter(main_string);
    printf("\nEnter the string you wish to delete: ");
    word_enter(word);
    string_search(main_string,word);
    string_disp(main_string);
    exit(EXIT_SUCCESS);
}
Adrian Mole
  • 43,040
  • 110
  • 45
  • 72

3 Answers3

6
*(index-m)=*(index++)

This is undefined behaviour. If you use a post- or pre-inc/decrement, don't use the same variable in the same expression again.

index[-m] = *index;
++index;
n. 1.8e9-where's-my-share m.
  • 102,958
  • 14
  • 123
  • 225
3

The problem (or, at least, one problem) is in your string_search function. The substring you extract from the given s argument is one character too long; thus, you won't get a match with the given d argument, unless you are very lucky.

To fix the problem, change the test condition in the while loop from i <= string_len(d) to i < string_len(d), like this:

void string_search(char* s, char* d)
{
    char* m = s;
    char word_buffer[20];
    char* buffer_index = word_buffer;
    while (m != &s[string_len(s) - string_len(d) + 1]) {
        buffer_index = word_buffer;
        if (*m == *d) {
            int i = 0;
            char* r = m;
            while (i < string_len(d) && *r != 0) { // Use i < string_len ... not i <=
                *(buffer_index++) = *(r++);
                i++;
            }
            *buffer_index = 0;
            if (string_comp(word_buffer, d) == 0) {
                printf("\nInvoking deletion sequence\n");
                string_deletion(m, string_len(d));
            }
        }
        m++;
    }
}

Also, be sure to address the issue of undefined behaviour highlighted in this answer (my MSVC compiler didn't spot that one, but clang-cl did)!

Adrian Mole
  • 43,040
  • 110
  • 45
  • 72
  • Um, how so? For instance, if the substring I intend to remove is 5 characters long, then I suppose the buffer will input 5 characters as well, won't it? – LordObnoxious Sep 06 '21 at 15:22
  • 1
    Yes. But you start counting at **zero** (as you should); so, when `i == 5` you have copied **six** characters. Try what I did: put a line at the top of your `string_comp` function that prints out the two strings it is given - you'll see that the first is one character longer than the second. – Adrian Mole Sep 06 '21 at 15:25
  • This fixes one bug. The answer from @n. 1.8e9-where's-my-share m., specifically addresses the bug in function `string_deletion`. – Jonathon S. Sep 06 '21 at 15:26
  • 1
    @JonathonS. Yes, indeed. That's why I added the footnote, linking to that answer. I *could* have included an explanation myself, but that would have been paramount to plagiarism, as they posted their answer before I even realized that bug was there. – Adrian Mole Sep 06 '21 at 15:27
  • @AdrianMole, that makes sense. How silly of me! – LordObnoxious Sep 06 '21 at 15:44
1

I would not reinvent the wheel:

char *string_deletion(char *s, size_t m)
{
    memmove(s, s + m, strlen(s+m) + 1);
    return s;
}
0___________
  • 47,100
  • 4
  • 27
  • 62