To begin with, I am a novie in C. So please bear with me.
I am referring a tutorial on pointers, which asked me to write a function to find a substring (and if found, the function should return the location of the substring in the original string).
I wrote the code and it works perfectly, the only problem is its too lengthy and I was wondering, if there was a way I can make it less complex.
Following is the code -
*s - contains the base address of the string,
*t - contains the base address of the substring,
num - contains the number of characters in substring (calculated by using strlen)
char *search(char *s, char *t, int num)
{
int i = 0, flag = 0;
/* increment str1 until first matching character (of substring) is encountered */
while((*s != *t) && (*s != '\0'))
{
s++;
}
if(*s == *t)
{
/* comparing the str and substr, and incrementing flag.. if flag is incremented num times, the strings match */
while((*(s+i) == *(t+i)) && (i<num))
{
flag++;
i++;
}
}
if(flag == num)
return s;
else
/* recursive function - str is incremented by 1, to start new comparison */
return search((s+1), t, num);
}
Any help would be appreaciated. Thank you, in advance.
I don't think you need to special-case finding the first character:
char * search(char *s, char *t, int num)
{
while (*s) {
int i;
for (i = 0; i < num; i++) {
if (!s[i]) {
return NULL;
}
if (s[i] != t[i]) {
break;
}
}
if (i == num) {
return s;
}
s++;
}
return NULL;
}
I think it's alread done quite well, just a few litte things:
char * search(char *s, char *t, int num)
{
int i = 0, flag = 0;
/* increment str1 until first matching character (of substring) is encountered */
/* It can be written on one line: */
while((*s != *t) && (*s != '\0')) s++;
/* comparing the str and substr, and incrementing flag.. if flag is incremented num times, the strings match */
/* The if is not needed, a for loop is shorter: */
for(; (*(s+i) == *(t+i)) && (i<num); flag++, i++);
if(flag == num)
return s;
else
/* recursive function - str is incremented by 1, to start new comparison */
return search((s+1), t, num);
}
You can use the strstr() function
return strstr(s, t);
http://www.tutorialspoint.com/c_standard_library/c_function_strstr.htm
Related
The function is supposed to work similarly to the strpbrk function in C. When I run the code, I get a segmentation fault. I did a rubber duck debug yet couldn't figure out any problem with the code. I am using a gcc compiler on WSL. The main.h header file contains the function declaration char *_strpbrk(char *s, char *accept). Please what am I missing?
#include "main.h"
/**
* _strpbrk - searches the string s for any of a set of bytes
*
* #s: String to be searched
* #accept: Substring of bytes to search for
* Return: Return a pointer to the byte in s that matches one of the bytes in
* accept, or NULL if no such byte is found
*/
char *_strpbrk(char *s, char *accept)
{
int i, j, check = 0, position = 0;
i = 0;
while (*(s + i) != '\0')
{
for (j = 0; *(accept + j) != '\0'; j++) /* Check if character of s in focus is a character in accept. Break out of the for loop if true*/
{
if (*(s + i) == *(accept + j))
{
check = 1;
position = i;
break;
}
}
if (check == 1) /* check if the character of s in focus was found to be in accept. Break out of the while loop if true */
{
break;
}
i++;
}
if (position == 0) /* Check for return value. Return null if whole string traversed*/
{
return ('\0');
}
else
{
return (s + position);
}
}
Forgot to mention that the gcc flags -Wall -pedantic -Werror -Wextra -std=gnu89 are used during compilation.
Do not use _ as a prefix.
This task shows how useful is use of the functions
char *mystrchr(const char *str, const char c)
{
while(*str)
{
if(*str == c) return (char *)str;
str++;
}
return NULL;
}
char *mystrbrk(const char *str, const char *brk)
{
while(*str)
{
if(mystrchr(brk, *str)) return (char *)str;
str++;
}
return NULL;
}
Now your code:
return ('\0');
This is not returning pointer. You are lucky as '\0' will convert to pointer NULL. Basically, it is very hard to analyze as you overthink many things.
#include "main.h"
/**
* _strpbrk - searches the string s for any of a set of bytes
*
* #s: String to be searched
* #accept: Substring of bytes to search for
* Return: Return a pointer to the byte in s that matches one of the bytes in
* accept, or NULL if no such byte is found
*/
char *_strpbrk(char *s, char *accept)
{
int i, j, check = 0, position = 0;
i = 0;
while (*(s + i) != '\0')
{
for (j = 0; *(accept + j) != '\0'; j++) /* Check if character of s in focus is a character in accept. Break out of the for loop if true*/
{
if (*(s + i) == *(accept + j))
{
check = 1;
position = i;
break;
}
}
if (check == 1) /* check if the character of s in focus was found to be in accept. Break out of the while loop if true */
{
break;
}
i++;
}
if (position == 0) /* Check for return value. Return null if whole string traversed*/
{
return ('\0');
}
else
{
return (s + position);
}
}
I am in the stage of preparing myself for exams, and the thing that I m least proud of are my skills with strings. What I need to do is remove a word from a sentence, without using <string.h> library at all.
This is what I've got so far. It keeps showing me that certain variables are not declared, such as start and end.
#include <stdio.h>
/* Side function to count the number of letters of the word we wish to remove */
int count(char *s) {
int counter = 0;
while (*s++) {
counter++;
s--;
return counter;
}
/* Function to remove a word from a sentence */
char *remove_word(const char *s1, const char *s2) {
int counter2 = 0;
/* We must remember where the string started */
const char *toReturn = s1;
/* Trigger for removing the word */
int found = 1;
/* First we need to find the word we wish to remove [Don't want to
use string.h library for anything associated with the task */
while (*s1 != '\0') {
const char *p = s1;
const char *q = s2;
if (*p == *q)
const char *start = p;
while (*p++ == *q++) {
counter2++;
if (*q != '\0' && counter2 < count(s2))
found = 0;
else {
const char *end = q;
}
}
/* Rewriting the end of a sentence to the beginning of the found word */
if (found) {
while (*start++ = *end++)
;
}
s1++;
}
return toReturn;
}
void insert(char niz[], int size) {
char character = getchar();
if (character == '\n')
character = getchar();
int i = 0;
while (i < size - 1 && character != '\n') {
array[i] = character;
i++;
character = getchar();
}
array[i] = '\0';
}
int main() {
char stringFirst[100];
char stringSecond[20];
printf("Type your text here: [NOT MORE THAN 100 CHARACTERS]\n");
insert(stringFirst, 100);
printf("\nInsert the word you wish to remove from your text.");
insert(stringSecond, 20);
printf("\nAfter removing the word, the text looks like this now: %s", stringFirst);
return 0;
}
your code is badly formed, i strongly suggest compiling with:
gcc -ansi -Wall -pedantic -Werror -D_DEBUG -g (or similar)
start with declaring your variables at the beginning of the function block, they are known only inside the block they are declared in.
your count function is buggy, missing a closing '}' (it doesn't compile)
should be something like
size_t Strlen(const char *s)
{
size_t size = 0;
for (; *s != '\n'; ++s, ++size)
{}
return size;
}
implementing memmove is much more efficient then copy char by char
I reformatted you code for small indentation problems and indeed indentation problems indicate real issues:
There is a missing } in count. It should read:
/* Side function to count the number of letters of the word we wish to remove */
int count(char *s) {
int counter = 0;
while (*s++) {
counter++;
}
return counter;
}
or better:
/* Side function to count the number of letters of the word we wish to remove */
int count(const char *s) {
const char *s0 = s;
while (*s++) {
continue;
}
return s - s0;
}
This function counts the number of bytes in the string, an almost exact clone of strlen except for the return type int instead of size_t. Note also that you do not actually use nor need this function.
Your function insert does not handle EOF gracefully and refuses an empty line. Why not read a line with fgets() and strip the newline manually:
char *input(char buf[], size_t size) {
size_t i;
if (!fgets(buf, size, stdin))
return NULL;
for (i = 0; buf[i]; i++) {
if (buf[i] == '\n') {
buf[i] = '\0';
break;
}
}
return buf;
}
In function remove_word, you should define start and end with a larger scope, typically the outer while loop's body. Furthermore s1 should have type char *, not const char *, as the phrase will be modified in place.
You should only increment p and q if the test succeeds and you should check that p and q are not both at the end of their strings.
last but not least: you do not call remove_word in the main function.
The complete code can be simplified into this:
#include <stdio.h>
/* Function to remove a word from a sentence */
char *remove_word(char *s1, const char *s2) {
if (*s2 != '\0') {
char *dst, *src, *p;
const char *q;
dst = src = s1;
while (*src != '\0') {
for (p = src, q = s2; *q != '\0' && *p == *q; p++, q++)
continue;
if (*q == '\0') {
src = p; /* the word was found, skip it */
} else {
*dst++ = *src++; /* otherwise, copy this character */
}
}
*dst = '\0'; /* put the null terminator if the string was shortened */
}
return s1;
}
char *input(char buf[], size_t size) {
size_t i;
if (!fgets(buf, size, stdin))
return NULL;
for (i = 0; buf[i]; i++) {
if (buf[i] == '\n') {
buf[i] = '\0';
break;
}
}
return buf;
}
int main() {
char stringFirst[102];
char stringSecond[22];
printf("Type your text here, up to 100 characters:\n");
if (!input(stringFirst, sizeof stringFirst))
return 1;
printf("\nInsert the word you wish to remove from your text: ");
if (!input(stringSecond, sizeof stringSecond))
return 1;
printf("\nAfter removing the word, the text looks like this now: %s\n",
remove_word(stringFirst, stringSecond));
return 0;
}
Your start and end pointers are defined within a block which makes their scope limited within that block. So, they are not visible to other parts of your code, and if you attempt to reference them outside their scope, the compiler will complain and throw an error. You should declare them at the beginning of the function block.
That said, consider the following approach to delete a word from a string:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int delete_word(char *buf,
const char *word);
int main(void)
{
const char word_to_delete[] = "boy";
fputs("Enter string: ", stdout);
char buf[256];
fgets(buf, sizeof(buf), stdin);
if (delete_word(buf, word_to_delete))
{
printf("Word %s deleted from buf: ", word_to_delete);
puts(buf);
}
else
{
printf("Word %s not found in buf: ", word_to_delete);
puts(buf);
}
system("PAUSE");
return 0;
}
int chDelimit(int ch)
{
return
(ch == '\n' || ch == '\t') ||
(ch >= ' ' && ch <= '/') ||
(ch >= ':' && ch <= '#') ||
(ch >= '[' && ch <= '`') ||
(ch >= '{' && ch <= '~') ||
(ch == '\0');
}
char *find_pattern(char *buf,
const char *pattern)
{
size_t n = 0;
while (*buf)
{
while (buf[n] && pattern[n])
{
if (buf[n] != pattern[n])
{
break;
}
n++;
}
if (!pattern[n])
{
return buf;
}
else if (!*buf)
{
return NULL;
}
n = 0;
buf++;
}
return NULL;
}
char *find_word(char *buf,
const char *word)
{
char *ptr;
size_t wlen;
wlen = strlen(word);
ptr = find_pattern(buf, word);
if (!ptr)
{
return NULL;
}
else if (ptr == buf)
{
if (chDelimit(buf[wlen]))
{
return ptr;
}
}
else
{
if (chDelimit(ptr[-1]) &&
chDelimit(ptr[wlen]))
{
return ptr;
}
}
ptr += wlen;
ptr = find_pattern(ptr, word);
while (ptr)
{
if (chDelimit(ptr[-1]) &&
chDelimit(ptr[wlen]))
{
return ptr;
}
ptr += wlen;
ptr = find_pattern(ptr, word);
}
return NULL;
}
int delete_word(char *buf,
const char *word)
{
size_t n;
size_t wlen;
char *tmp;
char *ptr;
wlen = strlen(word);
ptr = find_word(buf, word);
if (!ptr)
{
return 0;
}
else
{
n = ptr - buf;
tmp = ptr + wlen;
}
ptr = find_word(tmp, word);
while (ptr)
{
while (tmp < ptr)
{
buf[n++] = *tmp++;
}
tmp = ptr + wlen;
ptr = find_word(tmp, word);
}
strcpy(buf + n, tmp);
return 1;
}
If you have to do it manually, just loop over the indicies of your string to find the first one that matches and than you’ll have a second loop that loops for all the others that matches and resets all and jumps to the next index of the first loop if not matched something in order to continue the searching. If I recall accuretaly, all strings in C are accesible just like arrays, you’ll have to figure it out how. Don’t afraid, those principles are easy! C is an easy langugae, thiught very long to write.
In order to remove: store the first part in an array, store the second part in an array, alloc a new space for both of them and concatinate them there.
Thanks, hit the upvote button.
Vitali
EDIT: use \0 to terminate your newly created string.
I'm trying to write a recursive function which remove all duplicate chars from a given string recursively.
For example "Hello world" -> "Helo wrd".
The limitations I have are:
No loops allowed.
No more arguments can be added to the original function (remove_duplicates).
No functions from string.h library allowed, although I'm allowed to write them recursively.
I'm allowed to use another auxiliary recursive functions.
The function I wrote so far works only for short strings, it calls the function too many times. Any recommendations how to make it more efficient?
void remove_duplicates3(char string[], int index)//(str,RecursiveStrlen(str, 0)-1)
{
int length = RecursiveStrlen(string + 1, 0);
if (string[index] == '\0' || index == 0)
{
return;
}
if (string[0] != string[index])
{
remove_duplicates3(string, index - 1);
}
else
{
BackspaceString(string, index);
remove_duplicates3(string, length - 1);
}
remove_duplicates3(string + 1, length - 1);
}
int RecursiveStrlen(char str[], int index)
{
if (str[index] == '\0')
return index;
return RecursiveStrlen(str, index + 1);
}
void BackspaceString(char string[],int index)//deletes one char from string in a specific index
{
if (string[index] == '\0')//end of string
return;
string[index] = string[index + 1];
BackspaceString(string, index + 1);
}
Pure recursive solution:
void remove_char(char string[], char c, int read_index, int write_index) {
if (string[read_index] == 0) {
string[write_index] = 0;
return;
}
if (c == string[read_index]) {
remove_char(string, c, read_index + 1, write_index);
} else {
string[write_index] = string[read_index];
remove_char(string, c, read_index + 1, write_index + 1);
}
}
void remove_duplicates(char string[], int index) {
if (string[index] != 0 && string[index + 1] != 0) {
remove_char(string, string[index], index + 1, index + 1);
remove_duplicates(string, index + 1);
}
}
If you can use a global variable to store the resultant string, you could do this:
char result[30]="";
char over[30]="";
int check(char *over, char c)
{
if(*over != '\0')
{
if(*over == c)
{
return 1; //exists
}
else
{
return check(over+1, c);
}
}
return 0; //doesn't exist
}
int strLen(char *str)
{
if(*str=='\0')
{
return 0;
}
return strLen(str+1)+1;
}
void remove_duplicates(char *str)
{
if(*str != '\0')
{
if(check(over, *str)==0)
{
int len=strLen(result);
result[len++]=*str;
result[len]='\0';
len=strLen(over);
over[len++]=*str;
over[len]='\0';
}
remove_duplicates(str+1);
}
}
The resultant string is stored in result and over is a string which will store the already encountered characters as a string. over is checked by the check() function against a character c to return 0 if c was not found in over.
check() checks the value of over to determine if its argument c is present in over.
remove_duplicates() will check each character in the input string str. If the character was not encountered before in str, it is added to the list of already encountered characters to over and also appended to the result string.
This goes on till the input string str is over.
If your string is having only ASCII characters -
int arr[256] = {0};
/*
* str - Input string
* presult - Pointer to the buffer contain result
*/
void remove_duplicates(char *str, char *presult)
{
if(*str != '\0')
{
if(arr[*str] == 0)
{
*presult = *str;
arr[*str] = 1;
remove_duplicates(str+1, presult+1);
}
remove_duplicates(str+1, presult);
}
}
Simple Recursive Solution
I originally wrote this function in Scheme, but have translated it into C for you.
/*
* #params
* src -> input string from which to remove duplicates
* dest -> output string (initially empty)
* iter -> elements visited (initially 0)
*/
void remove_Dups_recursively(char *src, char *dest, int iter){
if(strlen(src) <= 1){
dest = src;
return;
}
if(iter == strlen(src)){
return;
}
if(strchr(dest, src[iter]) == NULL){
dest[strlen(dest)] = src[iter];
iter++;
remov(src, dest, iter);
}
else{
iter++;
remov(src, dest, iter);
}
}
i wanted to write a code which would allow me to find a position of a fist occurence of a letter, this is what i have come up so far. As you can see, what the function returns is actually a value and not the index. Is there a way to find it without simply giving the initial value of index as in the code no.2?
char *recFirstPosition(char * source, int letter)
{
if(*source == letter)
return *source;
if (*source =='\0')
return 0;
recFirstPosition(++source, letter);
}
char *recFirstPosition(char * source, int letter, int index)
{
if(*(source+index) == letter)
return index;
if (*(source+index) =='\0')
return 0;
recFirstPosition(source, letter, ++index);
}
Simply detach * from the first return and add return for the recursive call of your first version.
char *recFirstPosition(char * source, int letter)
{
if(*source == letter)
return source;
if (*source =='\0')
return 0;
return recFirstPosition(++source, letter);
}
It will make the code work. Your first version causes a type error.
The following is more readable version than the above:
char *recFirstPosition(char *source, char letter)
{
if (*source == '\0')
return NULL;
else if (*source == letter)
return source;
else
return recFirstPosition(++source, letter);
}
The above code also changed the type of the second parameter, but is written mostly inspired by several comments (Special thanks to Yuli and Dmitri).
And you may use the function as follows:
int main()
{
char *s = "Hello";
char *p = recFirstPosition(s, 'l');
if (p != NULL) {
int index = p - s;
printf("%s[%d] = %c\n", s, index, *p);
}
return 0;
}
Here is what I think could work. Please test it more since I did not have enough time to work with it
Edit: This return the position of the last occurrence but should give you enough to work with.
Edit2: Updated the function so now it works for
#include <stdio.h>
char *recFirstPosition(const char *s, int c, char *find){
if(s==NULL) return NULL;
if(*s == '\0') return (c == '\0') ? (char*)s : find;
if(*s == c) return (char*) s;
return recFirstPosition(s + 1, c, *s == c ? (char*)s : find);
}
int main ()
{
char str[] = "This is a sample string";
char * pch;
printf ("Looking for the 's' character in \"%s\"...\n",str);
pch=recFirstPosition(str,'s', NULL);
// Uncomment the while loop to get all instances positions
//while (pch!=NULL)
//{
printf ("found at %d\n",pch-str+1);
// pch=recFirstPosition(pch+1,'s',NULL);
//}
return 0;
}
output
Looking for the 's' character in "This is a sample string"...
found at 4
I need to check an array like 'Hello' and check when the terminating element is and then return a new line due to it. I've been trying code like this:
char * my_strchr(const char * string, int ch)
{
int count;
int length = strlen(string);
for(count = 0; count < length; count++)
{
if(string[count] == '\0')
{
return '\n' ;
}
}
My compiler does not like when I use these for some reason. In the function declaration for string it reads const char * string
The strlen function returns the string length without the NULL terminator. What this means is that your function does not return a char pointer, because your code will never get to the condition string[count] == '\0'.
Further, even if you did reach that condition, you are returning a char, not a char *, which is an error. Your function agreed to return a char * so some kind of char * needs to be returned, even if it points to NULL.
It also isn't clear from your function code, because it lacks a terminating bracket, but your function may never return anything.
Kind of guessing from your description, but perhaps something like this?
char * my_strchr(const char * string, int ch) {
int i;
int c;
for (i = 0; (c = string[i]) != '\0'; ++i) {
if (c == ch) return string + i; /* aka &string[i] */
}
return "\n"; /* got to the end w/o finding ch in string */
}
char *my_strchr(const char *string, int ch){
if(*string == '\0')
putchar('\n');//side effect
while(*string){
if(*string == ch)
return (char*)string;
++string;
}
return *string == ch ? (char*)string : NULL;
}