Splitting a string into substrings using C - c

I'm trying to make a program that splits the string based on a specific character.
Data Structure used:
typedef struct pieces {
char **members;
size_t len;
} pieces;
Function declarations:
pieces split (const char *s, const char c);
size_t charCount (const char *s, const char c);
char *slice (const char *s, int a, int b);
size_t indexOf (const char *s, const char c, size_t start);
charCount -> No. of times the char appeared in string.
indexOf -> Returns the index of a first occurrence of the given character inside the string, starting from the index start; i.e. indexOf("Stack Overflow", 'O', 0) == indexOf("Stack Overflow", 'O', 3)
I've implemented slice like this:
char *slice (const char *s, int a, int b)
{
if (a > b || a == b)
return NULL;
if (b > strlen(s)) // Only slice upto end if tried to slice out of index
b = strlen(s);
size_t len = b - a + 1;
char *slice = malloc(sizeof(char) * len);
for (size_t i = a; i < b; i++)
slice[i - a] = s[i];
slice[len - 1] = '\0';
return slice;
}
I'm confused on split function:
pieces split (const char *s, const char c)
{
// Is this the right way to make room for incoming slices ?
pieces arr;
arr.len = charCount(s, c) + 1;
arr.members = malloc(sizeof(char *) * arr.len);
// Should I do something like this to insert slices ?
for (size_t i = 0; i < strlen(s);)
{
int seperator_idx = indexOf(s, c, i);
char *piece = slice(s, i, seperator_idx);
arr.members[i] = piece; // Should I use strdup ??
i = seperator_idx + 1;
}
// What about the last slice ?
return arr;
}

There are some issues with the proposed prototypes:
pieces split(const char *s, const char c);
it is unclear if consecutive occurrences of c represent empty substrings or a single separator (as in strtok). Let's assume empty substrings should be accepted. const qualifying c is overkill and not meaningless in a prototype
size_t charCount(const char *s, const char c); same remark about const char c. Let's assume the null terminator is not part of the string so charCount("abc", '\0') is zero.
char *slice(const char *s, int a, int b); why are a and b typed int instead of size_t?
size_t indexOf(const char *s, const char c, size_t start); what should this function return in case c is not found the string starting from index start? Let's assume the offset of the end of string should be returned, as it is more convenient to implement slice.
With these conventions, indexOf and charCount can be written as:
#include <stddef.h>
size_t indexOf(const char *s, const char c, size_t start) {
while (s[start] && s[start] != c)
start++;
return start;
}
size_t charCount(const char *s, const char c) {
size_t count = 0;
while (*s) {
count += (*s++ == c);
}
return count;
}
Your slice function has multiple problems:
It should return an empty string if a == b,
it is confusing to name len something that is not the length of the substring. Either define len as size_t len = b - a; or use size_t size = b - a + 1;
it has undefined behavior if a is larger than strlen(s) and b > a.
you should gracefully return NULL in case of malloc() failure
Here is a modified version:
#include <stdlib.h>
/* return an empty string if a >= b */
char *slice(const char *s, size_t a, size_t b) {
size_t len = strlen(s);
if (a > len)
a = len;
if (b < a)
b = a;
char *slice = malloc(b - a + 1);
if (slice != NULL) {
for (size_t i = a; i < b; i++)
slice[i - a] = s[i];
slice[b - a] = '\0';
}
return slice;
}
The split function also has problems:
naming the pieces structure arr is confusing: it is not an array.
your allocation for arr.members is correct, but you should test if was allocated successful.
there is no need to strdup() the return value of slice, which was allocated with malloc().
you should use 2 separate index variables for the index i into the array arr.members and the index of the start of the substring.
the loop should be written with a test so split("", c) return a single empty string.
if indexOf returns the end of the string if c cannot be found, no special case is needed for the last slice.
Here is a modified version:
pieces split(const char *s, const char c) {
pieces arr;
arr.len = charCount(s, c) + 1;
arr.members = malloc(sizeof(*arr.members) * arr.len);
if (arr.members != NULL) {
for (size_t i = 0, start = 0; i < arr.len; i++) {
size_t end = indexOf(s, c, start);
arr.members[i] = slice(s, start, end);
start = end + 1;
if (arr.members[i] == NULL) {
/* free previous substrings and the members array */
while (i-- > 0) {
free(arr.members[i]);
}
free(arr.members);
arr.members = NULL;
break;
}
}
}
return arr;
}
Note these final remarks:
split as coded above works too if indexOf() returns (size_t)(-1) when the character is not found in the string.
recomputing the length of the string in slice() is wasteful. slice() should assume that the argument values are correct: 0 <= a < b <= strlen(s).
there is no direct way for split to return an error. Setting the members to NULL seems a workable solution.
instead of slice(), and assuming indexOf returns a valid offset into the string, you could use the POSIX standard function strndup():
arr.members[i] = strndup(s + start, end - start);

To split a string on 1 character, I would do something like:
#include <string.h>
#include <stdlib.h>
int count_words(char const *str, char const delim)
{
int count = 0;
int i = 0;
for (; str[i]; i++) {
// the next character is the beggining of a new string
if (str[i] == delim && str[i + 1] != delim)
count++;
}
// for safety
if (str[i - 1] != delim)
count++;
return count;
}
int word_length(char const *str, char const delim)
{
int length = 0;
// while we're on a valid character, increase the word length
while (str[length] && str[length] != delim)
length++;
return length;
}
pieces split(char const *str, char const delim)
{
// move the pointer until we're not on the delimiter
while (*str == delim)
str++;
// prepare the string array
pieces p;
p.len = count_words(str, delim);
p.members = malloc(p.len * sizeof(char *));
// for each string
for (int i = 0; i < p.len; i++) {
// copy the string
int length = word_length(str, delim);
p.members[i] = strndup(str, length);
// move the pointer until we're not on the delimiter
str += length;
while (*str == delim)
str++;
}
return p;
}

Related

remaking strcat, changes not reflecting to pointer

Hello guys so I am learning C and I am creating the strcat function and when I print out the values of dest at the index i concatenate a char at I get that char but when I return dest and print it out back in my main function the changes aren't reflected. Can someone please help me out? thanks.
#include <stdio.h>
#include <stdlib.h>
int size_s(char *str) {
int size = 0;
int index = 0;
while (str[index] != '\0') {
size += 1;
index += 1;
}
return (size + 1);
}
/*
* #function: strcat
* #desc: Takes in two char pointers and concatenates them. provided the destination has enough size otherwise undefined behavior can occur. Overwrites the null terminator
*/
char *strcat_s(char *dest, char *source)
{
int index_of_src = 0;
int index_of_dest = size_s(dest);
while (source[index_of_src] != '\0') {
*(dest + index_of_dest) = source[index_of_src];
index_of_src += 1;
index_of_dest += 1;
}
// Add Null terminator
*(dest + (index_of_dest + 1)) = '\0';
return dest;
}
int main(int argc, char **argv) {
char firstname[100];
scanf("%s", firstname);
char lastname[100];
scanf("%s", lastname);
int sizeofFirst = size_s(firstname);
printf("Sizeof first: %d\n", sizeofFirst);
int sizeofSecond = size_s(lastname);
printf("Sizeof second: %d\n", sizeofSecond);
char *concatinated = strcat_s(firstname, lastname);
printf("%s\n", concatinated);
}
The function size_s returns the index of the character after the zero-terminating character '\0' due to this return statement
return (size + 1);
So in this while loop
int index_of_src = 0;
int index_of_dest = size_s(dest);
while(source[index_of_src] != '\0')
{
*(dest + index_of_dest) = source[index_of_src];
index_of_src += 1;
index_of_dest += 1;
}
the array pointed to by the pointer dest is filled after the terminating zero character '\0'.
As a result this call of printf
printf("%s\n", concatinated);
outputs the initially stored string in the array firstname.
Rewrite the function size_s the following way
size_t size_s( const char *s )
{
size_t n = 0;
while ( s[n] != '\0' ) ++n;
return n;
}
In turn the function strcat_s that should be renamed because there is standard function strcat_s can look for example the following way
char * strcat_str( char *dest, const char *source )
{
size_t n = size_s( dest );
while ( ( *( dest + n++ ) = *source++ ) != '\0' );
return dest;
}
There are multiple issues in your code:
the size_s function really computes the size of the string, including the null terminator, but counting the null terminator is not helping for the task at hand, you should instead compute the length of the string, ie: the number of bytes before the null terminator, which is exactly the offset where to copy the second string at the end of the first.
*(dest + (index_of_dest + 1)) = '\0'; does not store the null terminator at the correct place: it places it one step too far. You should write *(dest + index_of_dest) = '\0'; or simply dest[ndex_of_dest] = '\0';
the name strcat_s may conflict with a library function of the same name defined in the infamous Annex K of the C Standard. A different name is preferable.
scanf("%s", firstname); is a security flaw: sufficient long input will cause a buffer overflow and carefully crafted input may allow the user to execute arbitrary code. Use scanf("%99s", firstname); to avoid this.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
int my_strlen(const char *str) {
int index = 0;
while (str[index] != '\0') {
index += 1;
}
return index;
}
/*
* #function: strcat
* #desc: Takes in two char pointers and concatenates them. provided the destination has enough size otherwise undefined behavior can occur. Overwrites the null terminator
*/
char *my_strcat(char *dest, const char *source) {
int index_of_src = 0;
int index_of_dest = my_strlen(dest);
while (source[index_of_src] != '\0') {
dest[index_of_dest] = source[index_of_src];
index_of_src += 1;
index_of_dest += 1;
}
// Add the null terminator
dest[index_of_dest] = '\0';
return dest;
}
int main(int argc, char **argv) {
char firstname[200];
char lastname[100];
if (scanf("%99s %99s", firstname, lastname) != 2)
return 1;
printf("length of first: %d\n", my_strlen(firstname));
printf("length of second: %d\n", my_strlen(lastname));
char *concatenated = my_strcat(firstname, lastname);
printf("%s\n", concatenated);
printf("length of concatenation: %d\n", my_strlen(concatenated));
return 0;
}

How do I pass an array of strings passed to a function to another function?

I'm new to pointers and I can already see how confusing they can be.
I have tried to look this up in several threads and google but they don't quite return what I'm looking for maybe out of my inexperience.
I'm being passed an array of strings and I have to pass it again to another function however I'm extremely confused on how to do this and don't know what * or & to use or where.
My code:
#include <stdlib.h>
#include <stdio.h>
char *ft_strcat(char *dest, char *src)
{
unsigned int c;
unsigned int count;
count = 0;
while (dest[count] != 0)
{
count++;
}
c = 0;
while (src[c] != '\0')
{
dest[c + count] = src[c];
c++;
}
dest[c + count] = 0;
return (dest);
}
int size_str(char *str)
{
int c;
c = 0;
while (str[c] != '\0')
{
c++;
}
return (c - 1);
}
int size_all(int size, char *strs[], char *sep)
{
int i;
int counter;
i = 0;
counter = 0;
counter += size_str(sep) * (size - 1);
while (i < size)
{
counter += size_str(strs[i]);
i++;
}
return (counter);
}
char *ft_strjoin(int size, char **strs, char *sep)
{
int i;
char *str;
str = malloc(sizeof(char) * size_all(size, strs, sep));
str = strs[0];
i = 1;
while (i < size)
{
str = ft_strcat(str, strs[i]);
}
return (str);
}
int main(void)
{
char *sep = " ";
char a1[] = "Batata";
char a2[] = "frita";
char a3[] = "\'e";
char a4[] = "melhor";
char a5[] = "que";
char a6[] = "Banana";
char *strs[] = {a1, a2, a3, a4, a5, a6};
char *final = ft_strjoin(6, strs, sep);
printf("%s", final);
}
I thought that size all would have to have an extra dereference operator on the declaration of the function and an reference operator when I call it, but this works just fine. Am I doing something wrong or am I just misunderstanding how pointers work? Don't I have to add an extra * each time I pass it?
Finally why doesn't while (src[c] != '\0') work?
In size_str:
There's nothing wrong with while (src[c] != '\0'), but return (c - 1); is causing an off-by-one error with your string lengths. The NUL byte wasn't counted in the loop, there's no need to subtract 1.
In ft_strcat:
The first loop is repeating work that could be handled by a call to size_str.
In ft_strjoin:
str = malloc(sizeof(char) * sizeall(size, strs, sep)));
sizeof (char) is uneccessary, as it is always 1. You need an additional 1 byte added to the length passed to malloc to make room for the NUL byte in your final string.
Remember that pointers are values too. str = strs[0]; assigns the pointer held in strs[0] to the the variable str. It does not copy the contents of strs[0]. You are overwriting the value returned by malloc with a pointer to a different piece of memory.
Instead, given this set of functions, initialize the memory returned by malloc to be the empty string, by setting the first byte to NUL, and use ft_strcat to concatenate the first string.
There's no need to continually reassign the result of ft_strcat, as you are already altering str, and the return value will never change.
A complete example. One must not forget to free the resulting string when it is no longer needed.
#include <stdlib.h>
#include <stdio.h>
int size_str(char *str)
{
int i = 0;
while (str[i])
i++;
return i;
}
char *ft_strcat(char *dest, char *src)
{
int i = 0,
length = size_str(dest);
do
dest[length++] = src[i];
while (src[i++]);
return dest;
}
int size_all(int size, char **strs, char *sep)
{
int total_length = size_str(sep) * (size - 1);
for (int i = 0; i < size; i++)
total_length += size_str(strs[i]);
return total_length;
}
char *ft_strjoin(int size, char **strs, char *sep)
{
char *result = malloc(1 + size_all(size, strs, sep));
result[0] = '\0';
ft_strcat(result, strs[0]);
for (int i = 1; i < size; i++) {
ft_strcat(result, sep);
ft_strcat(result, strs[i]);
}
return result;
}
int main(void)
{
char *sep = " ";
char a1[] = "Batata";
char a2[] = "frita";
char a3[] = "\'e";
char a4[] = "melhor";
char a5[] = "que";
char a6[] = "Banana";
char *strs[] = {a1, a2, a3, a4, a5, a6};
char *final = ft_strjoin(6, strs, sep);
printf("%s\n", final);
free(final);
}
Output:
Batata frita 'e melhor que Banana
I have worked lately about this problematic, string joint. I noticed that you forgot to add an if condition where the size would be 0. Moreover, the while loop need an iteration, which means that it will give you an infinite loop.
You can find as follows some adjustment to your code:
int i;
char *str;
int j;
int k;
i = 0;
k = 0;
str = (char *)malloc(sizeof(char) * sizeall(size, strs, sep) + 1));
if (size == 0)
return (0);
while (i < size)
{
j = 0;
while (strs[i][j])
str[k++] = strs[i][j++];
j = 0;
if (i < size - 1)
while (sep[j])
str[k++] = sep[j++];
i++;
}
str[k] = '\0';
return (str);
Feel free to ask me if there is something you did not understand, and good luck.

Reversing the word order in a string in place

I'm trying to reverse the order of words in a sentence in place, eg:
This sentences words are reversed.
becomes
reversed. are words sentences This
This is what I have so far, which almost works:
I use the strrev function to reverse the string, and then the inprev function to send each word to the strrev function individually, to reverse them back to the original orientation, but in reversed order.
Sending a pointer for the start and end of the strrev function might seem a bit silly, but it allows the same function to be used in inprev(), sending off a pointer to the start and end of individual words.
#include <stdio.h>
#include <string.h>
void strrev(char * start, char * end);
void inprev(char * start);
int main(void)
{
char str[] = "Foobar my friends, foobar";
char * end = (str + strlen(str) -1);
puts(str);
strrev(str, end);
puts(str);
inprev(str);
puts(str);
return 0;
}
void strrev(char * start, char * end)
{
char temp;
while (end > start)
{
temp = *start;
*start = *end;
*end = temp;
start++;
end--;
}
}
void inprev(char * start)
{
char * first = start;
char * spcpnt = start;
while (*spcpnt)
{
while (*spcpnt != ' ' && *spcpnt)
spcpnt++;
strrev(start, spcpnt-1); // removing the -1 sends the space on the
start = spcpnt++; // other side to be reversed, doesn't stop
// the problem.
}
}
Here is the output:
Foobar my friends, foobar
raboof ,sdneirf ym rabooF
foobarfriends, my Foobar
The problem is that the lack of a final space at the end of the final word means that a space is missing between that word and the preceeding one in the final string, and instead gets thrown onto the end of the last word, which was the first word in the original string. Sending off the space on the other side of the word only moves the problem elsewhere. Can anyone see a solution?
You just need to move the start pointer in the inprev function to skip the space between words. As this appears to be homework (correct me if I'm wrong) I'll just say that all you need to do is move the location of one operator.
But, this produces a problem, namely, the inprev performs a buffer overrun because the search isn't terminated properly. A better way to do it is:
while not end of string
search for start of word
start = start of word
search for end of word
strrev (start, end)
and that will take care of multiple spaces too. Also, U+0020 (ASCII 32, a space) is not the only white space character. There are standard library functions that test characters. They are in <ctype.h> and start with is..., e.g. isspace.
Sometimes things get easier if you don't use pointers but offsets.
The strspn() and strcspn() library functions more or less force you to use offsets,
and deal with the end-of-string condition quite nicely.
#include <stdio.h>
#include <string.h>
size_t revword(char *str);
void revmem(void *ptr, size_t len);
size_t revword(char *str) {
size_t pos,len;
for (pos=len=0; str[pos]; pos += len) {
len = strspn( str+pos, " \t\n\r");
if (len) continue;
len = strcspn( str+pos, " \t\n\r");
if (!len) continue;
revmem( str+pos, len );
}
revmem( str, pos );
return len;
}
void revmem(void *ptr, size_t len)
{
size_t idx;
char *str = (char*) ptr;
if (len-- < 2) return;
for (idx = 0; idx < len; idx++,len--) {
char tmp = str[idx];
str[idx] = str[len];
str[len] = tmp;
}
}
int main (int argc, char **argv)
{
if (!argv[1]) return 0;
revword(argv[1] );
printf("'%s'\n", argv[1] );
return 0;
}
Figured out a solution; here is my revised function that works properly.
void inprev(char * str)
{
_Bool inword = 0;
char * wordend;
char * wordstart;
while(*str)
{
if(!isspace(*str) && (inword == 0))
{
wordstart = str;
inword = 1;
}
else if (isspace(*str) && (inword == 1))
{
wordend = str-1;
inword = 0;
strrev(wordstart, wordend);
}
str++;
}
if (*str == '\0')
strrev(wordstart, str-1);
}
char * wordend is uneccessary as you can just pass str-1 to the strrev function, but it makes it a bit more clear what's happening.
The following algorithm is in-place and runs in 2 steps. First it reverses the entire string. Then it reverses each word.
#include <stdio.h>
void reverse(char *str, int len)
{
char *p = str;
char *e = str + len - 1;
while (p != e) {
*p ^= *e ^= *p ^= *e;
p++;
e--;
}
}
void reverse_words(char *str)
{
char *p;
// First, reverse the entire string
reverse(str, strlen(str));
// Then, reverse each word
p = str;
while (*p) {
char *e = p;
while (*e != ' ' && *e != '\0') {
e++;
}
reverse(p, e - p);
printf("%.*s%c", e - p, p, *e);
if (*e == '\0')
break;
else
p = e + 1;
}
}
int main(void) {
char buf[] = "Bob likes Alice";
reverse_words(buf);
return 0;
}
void reverse_str(char* const p, int i, int j) // helper to reverse string p from index i to j
{
char t;
for(; i < j ; i++, j--)
t=p[i], p[i]=p[j], p[j]=t;
}
void reverse_word_order(char* const p) // reverse order of words in string p
{
int i, j, len = strlen(p); // use i, j for start, end indices of each word
reverse_str(p, 0, len-1); // first reverse the whole string p
for(i = j = 0; i < len; i = j) // now reverse chars in each word of string p
{
for(; p[i] && isspace(p[i]);) // advance i to word begin
i++;
for(j = i; p[j] && !isspace(p[j]);) // advance j to past word end
j++;
reverse_str(p, i, j-1); // reverse chars in word between i, j-1
}
}

How to remove the character at a given index from a string in C?

How do I remove a character from a string?
If I have the string "abcdef" and I want to remove "b" how do I do that?
Removing the first character is easy with this code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char word[] = "abcdef";
char word2[10];
strcpy(word2, &word[1]);
printf("%s\n", word2);
return 0;
}
and
strncpy(word2, word, strlen(word) - 1);
will give me the string without the last character, but I still didn't figure out how to remove a char in the middle of a string.
memmove can handle overlapping areas, I would try something like that (not tested, maybe +-1 issue)
char word[] = "abcdef";
int idxToDel = 2;
memmove(&word[idxToDel], &word[idxToDel + 1], strlen(word) - idxToDel);
Before: "abcdef"
After: "abdef"
Try this :
void removeChar(char *str, char garbage) {
char *src, *dst;
for (src = dst = str; *src != '\0'; src++) {
*dst = *src;
if (*dst != garbage) dst++;
}
*dst = '\0';
}
Test program:
int main(void) {
char* str = malloc(strlen("abcdef")+1);
strcpy(str, "abcdef");
removeChar(str, 'b');
printf("%s", str);
free(str);
return 0;
}
Result:
>>acdef
My way to remove all specified chars:
void RemoveChars(char *s, char c)
{
int writer = 0, reader = 0;
while (s[reader])
{
if (s[reader]!=c)
{
s[writer++] = s[reader];
}
reader++;
}
s[writer]=0;
}
char a[]="string";
int toBeRemoved=2;
memmove(&a[toBeRemoved],&a[toBeRemoved+1],strlen(a)-toBeRemoved);
puts(a);
Try this . memmove will overlap it.
Tested.
Really surprised this hasn't been posted before.
strcpy(&str[idx_to_delete], &str[idx_to_delete + 1]);
Pretty efficient and simple. strcpy uses memmove on most implementations.
int chartoremove = 1;
strncpy(word2, word, chartoremove);
strncpy(((char*)word2)+chartoremove, ((char*)word)+chartoremove+1,
strlen(word)-1-chartoremove);
Ugly as hell
The following will extends the problem a bit by removing from the first string argument any character that occurs in the second string argument.
/*
* delete one character from a string
*/
static void
_strdelchr( char *s, size_t i, size_t *a, size_t *b)
{
size_t j;
if( *a == *b)
*a = i - 1;
else
for( j = *b + 1; j < i; j++)
s[++(*a)] = s[j];
*b = i;
}
/*
* delete all occurrences of characters in search from s
* returns nr. of deleted characters
*/
size_t
strdelstr( char *s, const char *search)
{
size_t l = strlen(s);
size_t n = strlen(search);
size_t i;
size_t a = 0;
size_t b = 0;
for( i = 0; i < l; i++)
if( memchr( search, s[i], n))
_strdelchr( s, i, &a, &b);
_strdelchr( s, l, &a, &b);
s[++a] = '\0';
return l - a;
}
This is an example of removing vowels from a string
#include <stdio.h>
#include <string.h>
void lower_str_and_remove_vowel(int sz, char str[])
{
for(int i = 0; i < sz; i++)
{
str[i] = tolower(str[i]);
if(str[i] == 'a' || str[i] == 'e' || str[i] == 'i' || str[i] == 'o' || str[i] == 'u')
{
for(int j = i; j < sz; j++)
{
str[j] = str[j + 1];
}
sz--;
i--;
}
}
}
int main(void)
{
char str[101];
gets(str);
int sz = strlen(str);// size of string
lower_str_and_remove_vowel(sz, str);
puts(str);
}
Input:
tour
Output:
tr
Use strcat() to concatenate strings.
But strcat() doesn't allow overlapping so you'd need to create a new string to hold the output.
I tried with strncpy() and snprintf().
int ridx = 1;
strncpy(word2,word,ridx);
snprintf(word2+ridx,10-ridx,"%s",&word[ridx+1]);
Another solution, using memmove() along with index() and sizeof():
char buf[100] = "abcdef";
char remove = 'b';
char* c;
if ((c = index(buf, remove)) != NULL) {
size_t len_left = sizeof(buf) - (c+1-buf);
memmove(c, c+1, len_left);
}
buf[] now contains "acdef"
This might be one of the fastest ones, if you pass the index:
void removeChar(char *str, unsigned int index) {
char *src;
for (src = str+index; *src != '\0'; *src = *(src+1),++src) ;
*src = '\0';
}
This code will delete all characters that you enter from string
#include <stdio.h>
#include <string.h>
#define SIZE 1000
char *erase_c(char *p, int ch)
{
char *ptr;
while (ptr = strchr(p, ch))
strcpy(ptr, ptr + 1);
return p;
}
int main()
{
char str[SIZE];
int ch;
printf("Enter a string\n");
gets(str);
printf("Enter the character to delete\n");
ch = getchar();
erase_c(str, ch);
puts(str);
return 0;
}
input
a man, a plan, a canal Panama
output
A mn, pln, cnl, Pnm!
Edit : Updated the code zstring_remove_chr() according to the latest version of the library.
From a BSD licensed string processing library for C, called zString
https://github.com/fnoyanisi/zString
Function to remove a character
int zstring_search_chr(char *token,char s){
if (!token || s=='\0')
return 0;
for (;*token; token++)
if (*token == s)
return 1;
return 0;
}
char *zstring_remove_chr(char *str,const char *bad) {
char *src = str , *dst = str;
/* validate input */
if (!(str && bad))
return NULL;
while(*src)
if(zstring_search_chr(bad,*src))
src++;
else
*dst++ = *src++; /* assign first, then incement */
*dst='\0';
return str;
}
Exmaple Usage
char s[]="this is a trial string to test the function.";
char *d=" .";
printf("%s\n",zstring_remove_chr(s,d));
Example Output
thisisatrialstringtotestthefunction
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 50
void dele_char(char s[],char ch)
{
int i,j;
for(i=0;s[i]!='\0';i++)
{
if(s[i]==ch)
{
for(j=i;s[j]!='\0';j++)
s[j]=s[j+1];
i--;
}
}
}
int main()
{
char s[MAX],ch;
printf("Enter the string\n");
gets(s);
printf("Enter The char to be deleted\n");
scanf("%c",&ch);
dele_char(s,ch);
printf("After Deletion:= %s\n",s);
return 0;
}
#include <stdio.h>
#include <string.h>
int main(){
char ch[15],ch1[15];
int i;
gets(ch); // the original string
for (i=0;i<strlen(ch);i++){
while (ch[i]==ch[i+1]){
strncpy(ch1,ch,i+1); //ch1 contains all the characters up to and including x
ch1[i]='\0'; //removing x from ch1
strcpy(ch,&ch[i+1]); //(shrinking ch) removing all the characters up to and including x from ch
strcat(ch1,ch); //rejoining both parts
strcpy(ch,ch1); //just wanna stay classy
}
}
puts(ch);
}
Let's suppose that x is the "symbol" of the character you want to remove
,my idea was to divide the string into 2 parts:
1st part will countain all the characters from the index 0 till (and including) the target character x.
2nd part countains all the characters after x (not including x)
Now all you have to do is to rejoin both parts.
This is what you may be looking for while counter is the index.
#include <stdio.h>
int main(){
char str[20];
int i,counter;
gets(str);
scanf("%d", &counter);
for (i= counter+1; str[i]!='\0'; i++){
str[i-1]=str[i];
}
str[i-1]=0;
puts(str);
return 0;
}
I know that the question is very old, but I will leave my implementation here:
char *ft_strdelchr(const char *str,char c)
{
int i;
int j;
char *s;
char *newstr;
i = 0;
j = 0;
// cast to char* to be able to modify, bc the param is const
// you guys can remove this and change the param too
s = (char*)str;
// malloc the new string with the necessary length.
// obs: strcountchr returns int number of c(haracters) inside s(tring)
if (!(newstr = malloc(ft_strlen(s) - ft_strcountchr(s, c) + 1 * sizeof(char))))
return (NULL);
while (s[i])
{
if (s[i] != c)
{
newstr[j] = s[i];
j++;
}
i++;
}
return (newstr);
}
just throw to a new string the characters that are not equal to the character you want to remove.
Following should do it :
#include <stdio.h>
#include <string.h>
int main (int argc, char const* argv[])
{
char word[] = "abcde";
int i;
int len = strlen(word);
int rem = 1;
/* remove rem'th char from word */
for (i = rem; i < len - 1; i++) word[i] = word[i + 1];
if (i < len) word[i] = '\0';
printf("%s\n", word);
return 0;
}
This is a pretty basic way to do it:
void remove_character(char *string, int index) {
for (index; *(string + index) != '\0'; index++) {
*(string + index) = *(string + index + 1);
}
}
I am amazed none of the answers posted in more than 10 years mention this:
copying the string without the last byte with strncpy(word2, word, strlen(word)-1); is incorrect: the null terminator will not be set at word2[strlen(word) - 1]. Furthermore, this code would cause a crash if word is an empty string (which does not have a last character).
The function strncpy is not a good candidate for this problem. As a matter of fact, it is not recommended for any problem because it does not set a null terminator in the destination array if the n argument is less of equal to the source string length.
Here is a simple generic solution to copy a string while removing the character at offset pos, that does not assume pos to be a valid offset inside the string:
#include <stddef.h>
char *removeat_copy(char *dest, const char *src, size_t pos) {
size_t i;
for (i = 0; i < pos && src[i] != '\0'; i++) {
dest[i] = src[i];
}
for (; src[i] != '\0'; i++) {
dest[i] = src[i + 1];
}
dest[i] = '\0';
return dest;
}
This function also works if dest == src, but for removing the character in place in a modifiable string, use this more efficient version:
#include <stddef.h>
char *removeat_in_place(char *str, size_t pos) {
size_t i;
for (i = 0; i < pos && str[i] != '\0'; i++)
continue;
for (; str[i] != '\0'; i++)
str[i] = str[i + 1];
return str;
}
Finally, here are solutions using library functions:
#include <string.h>
char *removeat_copy(char *dest, const char *src, size_t pos) {
size_t len = strlen(src);
if (pos < len) {
memmove(dest, src, pos);
memmove(dest + pos, src + pos + 1, len - pos);
} else {
memmove(dest, src, len + 1);
}
return dest;
}
char *removeat_in_place(char *str, size_t pos) {
size_t len = strlen(str);
if (pos < len) {
memmove(str + pos, str + pos + 1, len - pos);
}
return str;
}
A convenient, simple and fast way to get rid of \0 is to copy the string without the last char (\0) with the help of strncpy instead of strcpy:
strncpy(newStrg,oldStrg,(strlen(oldStrg)-1));

Implementation of strspn( )

The definition of library function strspn is:
size_t strspn(const char *str, const char *chars)
/* Return number of leading characters at the beginning of the string `str`
which are all members of string `chars`. */
e.g. if str is "fecxdy" and chars is "abcdef" then the function would return 3, since f, e and c all appear somewhere in chars, giving 3 leading characters of str, and x is the first character of str which is not a member of chars.
Could someone help me write an implementation of strspn in C. The only library function I am allowed to call from the implementation is strlen?
The basic idea is to step through the string, one character at a time, and test if it's in the character set. If it's not, stop and return the answer. In pseudocode, that would look like:
count = 0
for each character c in str
if c is not in chars
break
count++
return count
The if c is not in chars test can be implemented by iterating through all of the characters of chars and testing if c matches any of the characters. Note that this is not the fastest implementation, since it involves stepping through the chars string for each character in str. A faster implementation would use a lookup table to test if c is not in chars.
I found this question while going over old exams. You weren't allowed to use indexing or any standard functions. Here's my attempt at a solution:
#include <stdio.h>
size_t myStrspn(const char *str1, const char *str2){
size_t i,j;
i=0;
while(*(str1+i)){
j=0;
while(*(str2+j)){
if(*(str1+i) == *(str2+j)){
break; //Found a match.
}
j++;
}
if(!*(str2+j)){
return i; //No match found.
}
i++;
}
return i;
}
void main(){
char s[] = "7803 Elm St.";
int n = 0;
n = myStrspn(s,"1234567890");
printf("The number length is %d. \n",n);
}
Here's the solution from the exam:
#include<stdio.h>
size_t strspn(const char* cs, const char* ct) {
size_t n;
const char* p;
for(n=0; *cs; cs++, n++) {
for(p=ct; *p && *p != *cs; p++)
;
if (!*p)
break;
}
return n;
}
For loops made it much more compact.
I think this should be pretty fast
size_t strspn(const unsigned char *str, const unsigned char *chars){
unsigned char ta[32]={0};
size_t i;
for(i=0;chars[i];++i)
ta[chars[i]>>3]|=0x1<<(chars[i]%8);
for(i=0;((ta[str[i]>>3]>>(str[i]%8))&0x1);++i);
return i;
}
Thanks to others for sanity checks.
A naive implementation of strspn() would iterate on the first string, as long as it finds the corresponding character in the second string:
#include <string.h>
size_t strspn(const char *str, const char *chars) {
size_t i = 0;
while (str[i] && strchr(chars, str[i]))
i++;
return i;
}
Given that you are not allowed to call strchr(), here is a naive native implementation:
size_t strspn(const char *str, const char *chars) {
size_t i, j;
for (i = 0; str[i] != '\0'; i++) {
for (j = 0; chars[j] != str[i]; j++) {
if (chars[j] == '\0')
return i; // char not found, return index so far
}
}
return i; // complete string matches, return length
}
Scanning the second string repeatedly can be costly. Here is an alternative that combines different methods depending on the length of chars, assuming 8-bit bytes:
size_t strspn(const char *str, const char *chars) {
size_t i = 0;
char c = chars[0];
if (c != '\0') { // if second string is empty, return 0
if (chars[1] == '\0') {
// second string has single char, use a simple loop
while (str[i] == c)
i++;
} else {
// second string has more characters, construct a bitmap
unsigned char x, bits[256 / 8] = { 0 };
for (i = 0; (x = chars[i]) != '\0'; i++)
bits[x >> 3] |= 1 << (x & 7);
// iterate while characters are found in the bitmap
for (i = 0; (x = str[i]), (bits[x >> 3] & (1 << (x & 7))); i++)
continue;
}
}
return i;
}
int my_strspn(const char *str1,const char *str2){
int i,k,counter=0;
for(i=0;str1[i]!='\0';i++){
if(counter != i) break;
for(k=0;str2[k]!='\0';k++){
if(str1[i]==str2[k])
counter++;
}
}
return counter;
}
Create a lookup table (a poor man's set) for all possible ASCII chars, and just lookup each character in str. This is worst case O(max(N,M)), where N is the number of characters in str and M is the number of characters in chars.
#include <string.h>
size_t strspn(const char *str, const char *chars) {
int i;
char ch[256] = {0};
for (i = 0; i < strlen(chars); i++) {
ch[chars[i]] = 1;
}
for (i = 0; i < strlen(str); i++) {
if (ch[str[i]] == 0) {
break;
}
}
return i;
}
This could also be solved without using strlen at all, assuming both strings are zero-terminated. The disadvantage of this solution is that one needs 256 bytes of memory for the lookup table.
Without touching a C-compiler for the last couple of years. From the top of my head something like this should work:
int spn = 0;
while(*str++ != '\0')
{
char *hay = chars;
bool match = false;
while(*hay++ != '\0')
{
if(*hay == *str)
{
match = true;
break;
}
}
if(match)
spn++;
else
return spn;
}
return spn;
Well, implementing a standard library for my OS, here is my solution (C++).
KCSTDLIB_API_FUNC(size_t DECL_CALL strspn(const char * str1, const char * str2))
{
size_t count = 0;
auto isin = [&](char c)
{
for (size_t x = 0; str2[x]; x++)
{
if (c == str2[x])
return true;
};
return false;
};
for (; isin(str1[count]); count++);
return count;
}

Resources