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);
}
*(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;
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)!
I would not reinvent the wheel:
char *string_deletion(char *s, size_t m)
{
memmove(s, s + m, strlen(s+m) + 1);
return s;
}
Related
A task I have is to recreate the function strrchr. I figured out a way to iterate backward from the input given and stopping at the character I need to stop at, but the string came out backwards obviously. I already had created a function to reverse a string so I used that to reverse it back to normal. It works, but somewhere in my while loop when stopping at the character, it adds extra characters. Please help! I don't understand why!
#include <stdio.h>
#include <string.h>
// #include <stddef.h>
int
main () {
char* my_strrchr(char* param_1, char param_2)
{
int i = strlen(param_1) - 1;
int q = 0;
char new[strlen(param_1)];
char *new_ptr = new;
while (i >= 0) {
new[q] = param_1[i];
printf("%c\n", new[q]);
if (param_1[i] == param_2) {
i = 0;
}
i--;
q++;
}
int size = strlen(new_ptr) - 1;
for (int i = 0, q = size; i < q; i++, q--) {
char temp = new_ptr[i];
new_ptr[i] = new_ptr[q];
new_ptr[q] = temp;
}
printf("%s", new_ptr);
return (char *)new_ptr;
}
char *phrase = "C Language is HARD.";
char c = 'g';
my_strrchr(phrase, c);
return 0;
}
You don't need to do anything fancy. Just walk the string from the beginning, updating a variable with the address of the character you're looking for every time it's found, and return it when you hit the end of the string (Unlike strchr(), where you return after the first match). That way you only need one pass through the string instead of the two times it takes if you first find the length and then go backwards.
#include <stdio.h>
#include <stdlib.h>
// Really should return a const char*. Silly standard.
char *my_strrchr(const char *s, int c) {
const char *pos = NULL;
while (*s) {
if ((unsigned char)*s == (unsigned char)c) pos = s;
s++;
}
if (c == 0) {
// If searching for '\0', return a pointer to the one
// at the end of the string
return (char *)s;
} else {
return (char *)pos;
}
}
int main(void){
const char *foo = "the quite wet duck quacks a lot";
puts(my_strrchr(foo, 'q'));
return 0;
}
Write function that gets a string s and char c that checks whether the char shows in s, if yes return a pointer to the first place that c shows in s
Here is my code. I am not sure what I did about "return the pointer", is this correct?:
#include <stdio.h>
char *foo(char s[], char c)
{
int i;
char *ptr;
for(i=0;s[i];i++)
{
if(s[i]==c)
{
printf("result: %d",i);
*ptr=i;
return ptr;
}
}
}
void main()
{
char s[]="Error404";// some string
char c='r';// some char
foo(s,c);
}
First of all, your specification is unclear. Before you start coding, make sure that the specification makes sense. It doesn't say what to do if you don't find the character, so you can't write this function before you know that.
Your function must always return something, even if the character was not found. A common way to implement this would be to return a null pointer in that case.
Your pointer should point at the found character, not at i which is an integer, that doesn't make any sense.
Correct the code into something like this:
char* foo (char s[], char c)
{
char *ptr = NULL;
for(int i=0; s[i]!='\0'; i++)
{
if(s[i]==c)
{
ptr = &s[i]; // point at the address of item number i in s
break;
}
}
return ptr; // will return NULL if not found, otherwise a pointer to the found item
}
If s is a string, then s[i] represents the ith char in the string, while s + i represents a pointer to the ith char in the string. So you want to return s + i. You probably also want to return NULL if the char is not found.
#include <stdio.h>
char *foo(char s[], char c)
{
int i;
for(i = 0; s[i]; i++)
{
if(s[i] == c)
return (s + i);
}
return (NULL);
}
I have a problem with reversing string using stack structure.
I made some code to reverse 'apple' to 'elppa' and seems like it worked well...
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_STACK_SIZE 5
typedef int element;
element stack[MAX_STACK_SIZE];
int top = -1;
void initialize() {
top = -1;
}
int isEmpty() {
return (top == -1);
}
int isFull() {
return (top == (MAX_STACK_SIZE - 1));
}
void push(element item) {
if (isFull()) {
printf("stack is full, cannot add element.\n");
}
else{
stack[++top] = item;
}
}
element pop() {
if (isEmpty()) {
printf("stack is empty\n");
}
else {
return stack[top--];
}
}
char* reverse(char* s) {
const int len = sizeof(s) + 1;
char* rstring = new char[len];
initialize();
for (int i = 0; i < len; i++) {
push(s[i]);
}
int tmp = 0;
while(isEmpty()==false){
rstring[tmp++]=pop();
}
for (int i = 0; i < len; i++) {
printf("%c\n", rstring[i]);
}
return rstring;
}
void main() {
char* str1 = "apple";
char* str2 = reverse(str1);
printf("before : %s \n", str1);
printf("after : %s \n", str2);
getchar();
}
the result is here I got the answer(elppa) but it also printed out some other characters what I wasn`t intended. Why I got this thing? It may something to do with memory array or something but do not know exactly what was happened memory. How to fix the problem?
You haven't taken into account the string termination character '\0'. You are printing the sting using %s with printf.
Once rstring has been calculated after unwinding the stack, you should append '\0' to rstring. Hopefully this will solve your problem.
By using sizeof you will get the data_type size (in this case, size of char*) in bytes. You should use strlen instead.
for ex: if the string="EXAM"
insert a char'x' after every char of a string
output must be string="EXXXAXMX".i have done program for that but i stored a string and then i inserted 'x'.but i want the pgm to get input string from user and insert a char 'x' after every char of that string.how to do it?
#include<stdio.h>
#include<conio.h>
#include<string.h>
void strexpand(char [],char []);
void main()
{
char name[]="EXAM";
int length;
clrscr();
length=strlen(name);
printf("\n\tName=%s Length=%d",name,length);
strexpand(name);
getch();
}
void strexpand(char name[])
{
int i;
while(name[i]!='\0')
{
i++;
}
if(name[i]=='\0')
{
name[8]=name[4];
name[6]=name[3];
name[4]=name[2];
name[2]=name[1];
name[1]='x';
name[3]='x';
name[5]='x';
name[7]='x';
printf("\n\n\tAltered string is=%s",name);
}
}
It should be something like this , the new string will be always 2 times bigger than the original , so we should allocate it as 2 times bigger string , and then just copy as i said on comments.
char* strexpand(char name[])
{
int length=0;
int i=0 ,j=0;
char* retValue =null;
while(name[length]!='\0')
{
length++;
}
length++;
retValue = malloc (sizeof(char* length * 2));
if(!retValue)
return null;
for(i=0;i<length;i++,j+=2)
{
retVal[j] = name[i];
retVal[j+1] = 'x';
}
//at this point j did got +=2
retVal[j] = '\0';
return retVal;
}
Fix
#include<stdio.h>
#include<conio.h>
#include<string.h>
void strexpand(char []);
void main()
{
char name[9];
strcpy(name, "EXAM");
int length;
length=strlen(name);
printf("\n\tName=%s Length=%d",name,length);
strexpand(name);
getch();
}
void strexpand(char name[])
{
int i=0;
while(name[i]!='\0')
{
i++;
}
if(name[i]=='\0')
{
name[7]=name[3];
name[5]=name[2];
name[3]=name[1];
name[1]=name[0];
name[0]='x';
name[2]='x';
name[4]='x';
name[6]='x';
name[8] = '\0';
printf("\n\n\tAltered string is=%s",name);
}
}
note1: This code assumes that the string has at most has 8 characters.
note2: Arrays are indexed from 0. The first element is array[0]
note3: the line name[8] = '\0'; takes care of closing the string since C strings are null-terminated. It is important to know that to store n chars in a C string you always need n+1 bytes.
Some explanation
void strexpand(char name[])
{
int i;
while(name[i]!='\0')
{
i++;
}
This part is problematic, becasue i will have some junk value. It should be
void strexpand(char name[])
{
int i = 0;
while(name[i]!='\0')
{
i++;
}
Also when using strexpand you assue that its parameter has at least 9 elements because of this line:
name[8]
When you give it a smaller string than 9 elements (as in your code) the code will try to access elements outside of allocated space, which will result in a segfault.
So, when you called it with "EXAM" the parameter looked like this in memory:
['E','X','A','M','\0']
Given this, name[5] was already problematic.
I am currently studying C and I can't get past this exercise. I must create a recursive function to reverse string1 into string2. Here is my code. I would gladly appreciate your help.
#include <stdio.h>
#define MAX 100
void reverse(char s1[],char s2[],int n,int j);
int main()
{
char string1[MAX]="How Are You Mate";
char string2[MAX]="";
int n=0;
int i=0;
int j=0;
for(i=0;string1[i]!='\0';i++)
n++;
reverse(string1,string2,n,j);
printf("String-a normal:\n%s\n",string1);
printf("String-a reverse:\n%s\n",string2);
return 0;
}
void reverse(char s1[],char s2[],int n,int j)
{
if(n>0)
{
s2[j]=s1[n];
reverse(s1,s2,n-1,j+1);
}
else
s2[j]='\0';
}
in-place (the caller could make a copy of the string before calling this function) string reverse with tail-recursion
void reverse (char *str, size_t len)
{
char tmp;
if (len-- < 2) return;
tmp = *str;
*str = str[len];
str[len] = tmp;
reverse (str+1, len -1);
}
O, if you don't want pointers:
void reverse (char str[], size_t len)
{
char tmp;
if (len-- < 2) return;
tmp = str[0];
str[0] = str[len];
str[len] = tmp;
reverse (str+1, len -1);
}
The reversing starts by copying the n-th character of string1 array into string2. The n-th character happens to be the null terminator. It becomes the first character of your new string, so the string looks empty to all standard C routines, including printf.
Calling
reverse(string1,string2,n-1,j);
from the main should fix the problem. The condition in the reverse should be changed from if(n>0) to if(n>=0) as well.
Although it does not save the resulting string anywhere, you get the idea.
#include <stdio.h>
void rev (const char* str);
int main () {
const char str[] = "!dlrow ,olleH";
printf("%s\n", str);
rev(str);
printf("\n");
return 0;
}
void rev (const char* str) {
char c = *str;
if (c != '\0') {
rev(str + 1);
printf("%c", c);
}
}
I have corrected the program. Please find the changes below
void reverse(char s1[],char s2[],int n,int j)
{
if(n>0)
{
s2[j]=s1[n-1];
reverse(s1,s2,--n,++j);
}
else
s2[j]='\0';
}
i recommend using library , size=strlen(array) in stead of
for(i=0;string1[i]!='\0';i++)
n++;
to count how many characters in arra