Function that divides the string with given delimiter - c

I have function named ft_split(char const *s, char c) that is supposed to take strings and delimiter char c and divide s into bunch of smaller strings.
It is 3rd or 4th day I am trying to solve it and my approach:
Calculates no. of characters in the string including 1 delimiter at the time (if space is delimiter so if there are 2 or more spaces in a row than it counts one space and not more. Why? That space is a memory for adding '\0' at the end of each splitted string)
It finds size (k) of characters between delimiters -> malloc memory -> copy from string to malloc -> copy from malloc to malloc ->start over.
But well... function shows segmentation fault. Debugger shows that after allocating "big" memory it does not go inside while loop, but straight to big[y][z] = small[z] after what it exits the function.
Any tips appreciated.
#include "libft.h"
#include <stdlib.h>
int ft_count(char const *s, char c)
{
int i;
int j;
i = 0;
j = 0;
while (s[i] != '\0')
{
i++;
if (s[i] == c)
{
i++;
while (s[i] == c)
{
i++;
j++;
}
}
}
return (i - j);
}
char **ft_split(char const *s, char c)
{
int i;
int k;
int y;
int z;
char *small;
char **big;
i = 0;
y = 0;
if (!(big = (char **)malloc((ft_count(s, c) + 1) * sizeof(char))))
return (0);
while (s[i] != '\0')
{
while (s[i] == c)
i++;
k = 0;
while (s[i] != c)
{
i++;
k++;
}
if (!(small = (char *)malloc(k * sizeof(char) + 1)))
return (0);
z = 0;
while (z < k)
{
small[z] = s[i - k + z];
z++;
}
small[k] = '\0';
z = 0;
while (z < k)
{
big[y][z] = small[z];
z++;
}
y++;
free(small);
}
big[y][i] = '\0';
return (big);
}
int main()
{
char a[] = "jestemzzbogiemzalfa";
ft_split(a, 'z');
}

I didn't get everything what the code is doing, but:
You have a char **big, it's a pointer-to-pointer-to-char, so presumably is supposed to point to an array of char *, which then point to strings. That would look like this:
[ big (char **) ] -> [ big[0] (char *) ][ big[1] (char *) ][ big[2] ... ]
| [
v v
[ big[0][0] (char) ] ...
[ big[0][1] (char) ]
[ big[0][2] (char) ]
[ ... ]
Here, when you call big = malloc(N * sizeof(char *)), you allocate space for the middle pointers, big[0] to big[N-1], the ones on the top right in the horizontal array. It still doesn't set them to anything, and doesn't reserve space for the final strings (big[0][x] etc.)
Instead, you'd need to do something like
big = malloc(N * sizeof(char *));
for (i = 0; i < N; i++) {
big[i] = malloc(k);
}
for each final string individually, with the correct size etc. Or just allocate a big area in one go, and split it among the final strings.
Now, in your code, it doesn't look like you're ever assigning anything to big[y], so they might be anything, which very likely explains the segfault when referencing big[y][z]. If you used calloc(), you'd now that big[y] was NULL, with malloc() it might be, or might not.
Also, here:
while (s[i] != '\0')
{
while (s[i] == c)
i++;
k = 0;
while (s[i] != c) /* here */
{
i++;
k++;
}
I wonder what happens if the end of string is reached at the while (s[i] != c), i.e. if s[i] is '\0' at that point? The loop should probably stop, but it doesn't look like it does.

There are multiple problems in the code:
the ft_count() function is incorrect: you increment i before testing for separators, hence the number is incorrect if the string starts with separators. You should instead count the number of transitions from separator to non-separator:
int ft_count(char const *s, char c)
{
char last;
int i;
int j;
last = c;
i = 0;
j = 0;
while (s[i] != '\0')
{
if (last == c && s[i] != c)
{
j++;
}
last = s[i];
i++;
}
return j;
}
Furthermore, the ft_split() functions is incorrect too:
the amount of memory allocated for the big array of pointers in invalid: you should multiply the number of elements by the element size, which is not char but char *.
you add an empty string at the end of the array if the string ends with separators. You should test for a null byte after skipping the separators.
you do not test for the null terminator when scanning for the separator after the item.
you do not store the small pointer into the big array of pointers. Instead of copying the string to big[y][...], you should just set big[y] = small and not free(small).
Here is a modified version:
char **ft_split(char const *s, char c)
{
int i;
int k;
int y;
int z;
char *small;
char **big;
if (!(big = (char **)malloc((ft_count(s, c) + 1) * sizeof(*big))))
return (0);
i = 0;
y = 0;
while (42) // aka 42 for ever :)
{
while (s[i] == c)
i++;
if (s[i] == '\0')
break;
k = 0;
while (s[i + k] != '\0' && s[i + k] != c)
{
k++;
}
if (!(small = (char *)malloc((k + 1) * sizeof(char))))
return (0);
z = 0;
while (z < k)
{
small[z] = s[i];
z++;
i++;
}
small[k] = '\0';
big[y] = small;
y++;
}
big[y] = NULL;
return (big);
}
42 rant:
Ces conventions de codage (la norminette) sont contre-productives! Les boucles for sont plus lisibles et plus sûres que ces while, les casts sur les valeurs de retour de malloc() sont inutiles et confusantes, les parenthèses autour de l'argument de return sont infantiles.

Related

How to go through a array of strings using pointers alone

I'm trying to create a function that will receive an array of strings and the size and will return a string made of the biggest ASCII value's letter of each word, and the size of the string has to be precised and I'm not allowed using operator [](which is my main issue).
so for:
char *strArr[SIZE] = { "hello", "and", "good", "morning" };
the function shall return a string with the word
"onor"
.
So i thought of creating a double for loop, first one will lead me into the location of each word in the array and the inside one will help me go through each word.
currently I'm having trouble finding the right format with my pointers to actually go through the letters of my first word.
I'm aware i haven't checked if my memory allocation is valid and also didn't free my memory yet as I'm trying to figure out whats wrong first.
char *bigLetters(char *str[], int size)
{
char *strNew = (char *)malloc((size + 1) * sizeof(char));
char max = 'a';
for (int i = 0; i < size; i++)
{
for (int j = 0; (*(str + i)+j) != NULL; j++)
{
if ((*(str + i) + j) >= max)
{
max = (*(str + i) + j);
}
}
*(strNew + i) = max;
}
*(strNew +(size+1)) = NULL;
return *(strNew);
}
void main()
{
char *strArr[SIZE] = { "hello", "and", "good", "morning" };
char *res = bigLetters(strArr, SIZE);
printf("The new string is --> %s\n", res);
system("pause");
}
It will be easier to use the pointers if you separate the string pointer from its character pointer. Also, the max needs to be reset for each string, and you were writing the final string terminator outside of the memory allocated. You also use NULL where you should be using the character '\0'.
Finally the function was returning the first character of the new string (which I later free).
#include <stdio.h>
#include <stdlib.h>
#define SIZE 4
char *bigLetters(char *str[], int size)
{
char *strNew = malloc(size + 1); // no cast or sizeof necessary
for (int i = 0; i < size; i++)
{
char ch;
char max = 'a'; // moved inside loop
char *ptr = *(str + i); // use a separate pointer
for (int j = 0; (ch = *(ptr + j)) != '\0'; j++) // pull out the character
{
if (ch > max) // >= is not necessary
{
max = ch;
}
}
*(strNew + i) = max;
}
*(strNew + size) = '\0'; // correct the bounds error
return strNew; // just the pointer not its target
}
int main(void) // correct signature
{
char *strArr[SIZE] = { "hello", "and", "good", "morning" };
char *res = bigLetters(strArr, SIZE);
printf("The new string is --> %s\n", res);
free(res); // clean up
system("pause");
}
Program output
The new string is --> onor
Press any key to continue . . .
If you didn't impose odd and unhelpful restrictions upon your coding, you'd be able to quickly see the problems with your code or even avoid making them in the first place. The problem is that the following statement makes no sense - you're comparing a char * with a char as you're only de-referencing str once.
if ((*(str + i) + j) >= max)
This is the same as writing
if ((str[i] + j) >= max)
which you can see the obvious mistake since what you're trying to write is the equivalent of
if ((str[i][j]) >= max)
which would be
if (*(*(str + i) + j) >= max)
Your compiler should be throwing up warnings because comparing between a pointer and an integer is rarely something you'd want to do.
You can use pointers as position indicators and advance them as needed.
#include <stdio.h>
#include <stdlib.h>
#define SIZE 4
char
biggest_ascii(char* str)
{
char c = 0;
int i;
for (i = 0; *str; str++)
if (*str > c)
c = *str;
return c;
}
int
main()
{
int i;
char* strArr[SIZE] = {"hello", "and", "good", "morning"};
char** ppch;// current string
char res_str[SIZE + 1] = {0};/* resulting string,
initilized to 0 to be 0-terminated */
char* pch;// current char position
for (i = 0, ppch = strArr, pch = res_str; i < SIZE; i++, ppch++, pch++)
*pch = biggest_ascii(*ppch);
printf("%s\n", res_str);
return 0;
}
First, (*(str + i)+j) isn't the good way.
You could replace all
(*(str + i) + j)
by :
str[i][j]
Then, you need to reset the max to "a", because it's 'o' when you leave the loop, so your condition become str[i][j] >= o which is not what you want. Do it before the second for.
And I would have used while instead of for for the first loop.
I edited your code and this version is working fine for me :
#include <stdlib.h>
char *bigLetters(char *str[], int size)
{
char *strNew = (char *)malloc((size + 1) * sizeof(char));
int i = 0;
while (i < size) {
char max = 'a';
for (int j = 0; str[i][j]; j++) {
if (str[i][j] >= max) {
max = str[i][j];
}
}
strNew[i] = max;
i++;
}
strNew[i] = '\0';
return strNew;
}
void main()
{
char *strArr[5] = { "hello", "and", "good", "morning"};
char *res = bigLetters(strArr, 4);
printf("The new string is --> %s\n", res);
return 0;
}
str[i] is equivalent to *(str + i) and str[i][j] is equivalent to *(*(str + i) + j).
In your code you are using (*(str + i) + j) which is incorrect.
When char *[] passed to function, it will decay to char **. So, in bigLetters(), you can give char **str as the parameter. Also, it is inline with you requirement - not allowed using operator [].
Instead of hardcoding the dimension SIZE in char *strArr[SIZE], you can give the empty [] and let the compiler assign the dimension based on the size of initializer. In your case, size of initializer is 4 as you have given 4 strings in the strArr initializer. You can compute the size of strArr like this:
sizeof(strArr)/sizeof(strArr[0]);
You can do:
#include <stdio.h>
#include <stdlib.h>
char *bigLetters(char **str, size_t size) {
char *strNew = calloc(size + 1, 1); // sizeof(char) is always 1
// calloc will initialize all bytes in the allocated storage to zero.
// You dont need to add the null terminating character at the end of strNew
if (strNew == NULL)
exit(EXIT_FAILURE);
for (size_t i = 0; i < size; i++) {
for (size_t j = 0; *(*(str + i)+j) != '\0'; j++) {
if (*(*(str + i) + j) > *(strNew + i)) {
// You can directly fill the allocated memory with biggest ASCII
*(strNew + i) = *(*(str + i) + j);
}
}
}
return strNew;
}
int main(void) {
char *strArr[] = { "hello", "and", "good", "morning" };
char *res = bigLetters(strArr, sizeof(strArr)/sizeof(strArr[0]));
if (res != NULL) {
printf("The new string is --> %s\n", res);
free (res);
}
else
printf("bigLetters returned NULL\n");
return 0;
}
Note that void return type main() is not as per standard. Instead, you should use int as return type of main().

Copying a string into a new array

I'm trying to read a string in an array, and if a character is not any of the excluded characters int a = ('a'||'e'||'i'||'o'||'u'||'y'||'w'||'h'); it should copy the character into a new array, then print it.
The code reads as:
void letter_remover (char b[])
{
int i;
char c[MAX];
int a = ('a'||'e'||'i'||'o'||'u'||'y'||'w'||'h');
for (i = 0; b[i] != '\0'; i++)
{
if (b[i] != a)
{
c[i] = b[i];
}
i++;
}
c[i] = '\0';
printf("New string without forbidden characters: %s\n", c);
}
However it only prints New string without forbidden characters: h, if the inputted array is, for example hello. I'd like the output of this to be ll (with h, e and o removed).
Use this:
if (b[i] != 'a' && b[i] != 'e' && b[i] != 'i' && b[i] != 'o' && b[i] != 'u' && b[i] != 'y' && b[i] != 'w' && b[i] != 'h')
The boolean OR operator just returns 0 or 1, it doesn't create an object that automatically tests against all the parameters to the operator.
You could also use the strchr() function to search for a character in a string.
char a[] = "aeiouywh";
for (i = 0; b[i] != '\0'; i++)
{
if (!strchr(a, b[i]))
{
c[i] = b[i];
}
i++;
}
c[i] = '\0';
int a = ('a'||'e'||'i'||'o'||'u'||'y'||'w'||'h');
...has an entirely different meaning than you expect. When you Boolean-OR together all those characters, a becomes 1. Since b[] contains no character value 1, no characters will be excluded. Also, your c[] is going to have empty slots if you had tested correctly.
You can use strcspn() to test if your string contains your forbidden characters. For example...
// snip
int i=0, j=0;
char * a = "aeiouywh";
while (b[i])
{
int idx = strcspn(&b[i], a);
if (idx >= 0)
{
if (idx > 0)
strncpy(&c[j], &b[i], idx);
j += idx;
i += idx + 1;
}
}
// etc...
Also, you must be sure c[] is large enough to contain all the characters that might be copied.

String tokenizer without using strtok()

I'm in the process of writing a string tokenizer without using strtok(). This is mainly for my own betterment and for a greater understanding of pointers. I think I almost have it, but I've been receiving the following errors:
myToc.c:25 warning: assignment makes integer from pointer without a cast
myToc.c:35 (same as above)
myToc.c:44 error: invalid type argument of 'unary *' (have 'int')
What I'm doing is looping through the string sent to the method, finding each delimiter, and replacing it with '\0.' The "ptr" array is supposed to have pointers to the separated substrings. This is what I have so far.
#include <string.h>
void myToc(char * str){
int spcCount = 0;
int ptrIndex = 0;
int n = strlen(str);
for(int i = 0; i < n; i++){
if(i != 0 && str[i] == ' ' && str[i-1] != ' '){
spcCount++;
}
}
//Pointer array; +1 for \0 character, +1 for one word more than number of spaces
int *ptr = (int *) calloc(spcCount+2, sizeof(char));
ptr[spcCount+1] = '\0';
//Used to differentiate separating spaces from unnecessary ones
char temp;
for(int j = 0; j < n; j++){
if(j == 0){
/*Line 25*/ ptr[ptrIndex] = &str[j];
temp = str[j];
ptrIndex++;
}
else{
if(str[j] == ' '){
temp = str[j];
str[j] = '\0';
}
else if(str[j] != ' ' && str[j] != '\0' && temp == ' '){
/*Line 35*/ ptr[ptrIndex] = &str[j];
temp = str[j];
ptrIndex++;
}
}
}
int k = 0;
while(ptr[k] != '\0'){
/*Line 44*/ printf("%s \n", *ptr[k]);
k++;
}
}
I can see where the errors are occurring but I'm not sure how to correct them. What should I do? Am I allocating memory correctly or is it just an issue with how I'm specifying the addresses?
You pointer array is wrong. It looks like you want:
char **ptr = calloc(spcCount+2, sizeof(char*));
Also, if I am reading your code correctly, there is no need for the null byte as this array is not a string.
In addition, you'll need to fix:
while(ptr[k] != '\0'){
/*Line 44*/ printf("%s \n", *ptr[k]);
k++;
}
The dereference is not required and if you remove the null ptr, this should work:
for ( k = 0; k < ptrIndex; k++ ){
/*Line 44*/ printf("%s \n", ptr[k]);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void myToc(char * str){
int spcCount = 0;
int ptrIndex = 0;
int n = strlen(str);
for(int i = 0; i < n; i++){
if(i != 0 && str[i] == ' ' && str[i-1] != ' '){
spcCount++;
}
}
char **ptr = calloc(spcCount+2, sizeof(char*));
//ptr[spcCount+1] = '\0';//0 initialized by calloc
char temp = ' ';//can simplify the code
for(int j = 0; j < n; j++){
if(str[j] == ' '){
temp = str[j];
str[j] = '\0';
} else if(str[j] != '\0' && temp == ' '){//can omit `str[j] != ' ' &&`
ptr[ptrIndex++] = &str[j];
temp = str[j];
}
}
int k = 0;
while(ptr[k] != NULL){//better use NULL
printf("%s \n", ptr[k++]);
}
free(ptr);
}
int main(){
char test1[] = "a b c";
myToc(test1);
char test2[] = "hello world";
myToc(test2);
return 0;
}
Update: I tried this at http://www.compileonline.com/compile_c99_online.php
with the fixes for lines 25, 35, and 44, and with a main function that called
myToc() twice. I initially encountered segfaults when trying to write null characters
to str[], but that was only because the strings I was passing were (apparently
non-modifiable) literals. The code below worked as desired when I allocated a text buffer and wrote the strings there before passing them in. This version also could be modified to return the array of pointers, which then would point to the tokens.
(The code below also works even when the string parameter is non-modifiable, as long as
myToc() makes a local copy of the string; but that would not have the desired effect if the purpose of the function is to return the list of tokens rather than just print them.)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void myToc(char * str){
int spcCount = 0;
int ptrIndex = 0;
int n = strlen(str);
for(int i = 0; i < n; i++){
if(i != 0 && str[i] == ' ' && str[i-1] != ' '){
spcCount++;
}
}
//Pointer array; +1 for one word more than number of spaces
char** ptr = (char**) calloc(spcCount+2, sizeof(char*));
//Used to differentiate separating spaces from unnecessary ones
char temp;
for(int j = 0; j < n; j++){
if(j == 0){
ptr[ptrIndex] = &str[j];
temp = str[j];
ptrIndex++;
}
else{
if(str[j] == ' '){
temp = str[j];
str[j] = '\0';
}
else if(str[j] != ' ' && str[j] != '\0' && temp == ' '){
ptr[ptrIndex] = &str[j];
temp = str[j];
ptrIndex++;
}
}
}
for (int k = 0; k < ptrIndex; ++k){
printf("%s \n", ptr[k]);
}
}
int main (int n, char** v)
{
char text[256];
strcpy(text, "a b c");
myToc(text);
printf("-----\n");
strcpy(text, "hello world");
myToc(text);
}
I would prefer simpler code, however. Basically you want a pointer to the first non-blank character in str[], then a pointer to each non-blank (other than the first) that is preceded by a blank. Your first loop almost gets this idea except it is looking for blanks preceded by non-blanks. (Also you could start that loop at i = 1 and avoid having to test i != 0 on each iteration.)
I might just allocate an array of char* of size sizeof(char*) * (n + 1)/2 to hold the pointers rather than looping over the string twice (that is, I'd omit the first loop, which is just to figure out the size of the array). In any case, if ptr[0] is non-blank I would write its address to the array; then looping for (int j = 1; j < n; ++j), write the address of str[j] to the array if str[j] is non-blank and str[j - 1] is blank--basically what you are doing, but with fewer ifs and fewer auxiliary variables.
Less code means less opportunity to introduce a bug, as long as the code is clean and makes sense.
Previous remarks:
int *ptr = declares an array of int. For an array of pointers to char, you want
char** ptr = (char**) calloc(spcCount+2, sizeof(char*));
The comment prior to that line also seems to indicate some confusion. There is no terminating null in your array of pointers, and you don't need to allocate space for one, so possibly spcCount+2 could be spcCount + 1.
This also is suspect:
while(ptr[k] != '\0')
It looks like it would work, given the way you used calloc (you do need spcCount+2 to make this work), but I would feel more secure writing something like this:
for (k = 0; k < ptrIndex; ++k)
I do not thing that is what caused the segfault, it just makes me a little uneasy to compare a pointer (ptr[k]) with \0 (which you would normally compare against a char).

Pushing characters in char array to index 0

I'm trying to build a string from f, being split at whitespace and read it into a struct.
f is the char array I'm iterating over.
I then copy the contents from tmp into ra1.callsign, and essentially empty the tmp char array.
What I want to do is have the the tmp variable start building from index 0 again, so that when I try to strcpy the second time round all the characters in tmp start from index 0.
The way I have it now, when it tries the line: strcpy(ra1.location, tmp) it doesn't copy anything, I think this is because at that point the first character in tmp doesn't appear until some time down the array.
char c;
char tmp[1000];
for (i = 0; i < len; ++i) {
c = f[i];
if (c != ' ') {
tmp[i] = c; //build string to be added
}
//add string to data structure
if (c == ' ') {
if (addTo == CALLSIGN) {
strncpy(ra1.callsign, tmp, strlen(tmp));
memset(tmp, '\0', strlen(tmp));
}
if (addTo == LOCATION) {
strcpy(ra1.location, tmp);
}
++addTo;
}
}
Hope this is clear enough, thanks.
You left out quite a few details in your code and I have made a number of assumptions.
So, using the assumptions that I have made (which you can see in the code below), I believe that this will do what you are trying to accomplish. There are much easier and cleaner ways to do this, but I am hoping that you can get a clear understanding of how it would work with your code.
I have basically added a terminating null character where it is required so the strlen() function will work correctly and utilized an extra variable called cur_size which can be used as an offset based on the current index i.
#include <string.h>
#include <stdio.h>
#define CALLSIGN 3U
#define LOCATION 5U
#define ARRAY_SIZE 50U
typedef struct
{
char callsign[ARRAY_SIZE];
char location[ARRAY_SIZE];
} MyStruct;
MyStruct ra1 = { .callsign = {0}, .location = {0} };
char f[] = "This is my character array. Let's see what happens.";
int main (void)
{
char c;
char tmp[ARRAY_SIZE];
unsigned char addTo = 0;
unsigned char i;
unsigned char cur_size = 0;
for(i = 0; i < sizeof(f); ++i)
{
c = f[i];
if(c != ' ')
{
tmp[i - cur_size] = c; //build string to be added
}
//add string to data structure
if(c == ' ')
{
tmp[i - cur_size] = '\0'; /* YOU NEED THIS FOR strlen(tmp) to work */
cur_size = i + 1;
if(addTo == CALLSIGN)
{
strncpy(ra1.callsign, tmp, strlen(tmp));
//memset(tmp, '\0', strlen(tmp));
}
else if (addTo == LOCATION)
{
strncpy(ra1.location, tmp, strlen(tmp));
}
++addTo;
}
}
for (i = 0; i < ARRAY_SIZE; i++)
{
printf("%c", ra1.callsign[i]);
}
printf("\r\n");
for (i = 0; i < ARRAY_SIZE; i++)
{
printf("%c", ra1.location[i]);
}
printf("\r\n");
return 0;
}

C program to remove repeated char from a string

I came across a interview question that asked to remove the repeated char from a given string, in-place.
So if the input was "hi there" the output expected was "hi ter". It was also told to consider only alphabetic repititions and all the
alphabets were lower case. I came up with the following program. I have comments to make my logic clear. But the program does not work as expectd for some inputs. If the input is "hii" it works, but if its "hi there" it fails. Please help.
#include <stdio.h>
int main()
{
char str[] = "programming is really cool"; // original string.
char hash[26] = {0}; // hash table.
int i,j; // loop counter.
// iterate through the input string char by char.
for(i=0,j=0;str[i];)
{
// if the char is not hashed.
if(!hash[str[i] - 'a'])
{
// hash it.
hash[str[i] - 'a'] = 1;
// copy the char at index i to index j.
str[j++] = str[i++];
}
else
{
// move to next char of the original string.
// do not increment j, so that later we can over-write the repeated char.
i++;
}
}
// add a null char.
str[j] = 0;
// print it.
printf("%s\n",str); // "progamin s ely c" expected.
return 0;
}
when str[i] is a non-alphabet, say a space and when you do:
hash[str[i] - 'a']
your program can blow.
ASCII value of space is 32 and that of a is 97 so you are effectively accessing array hash with a negative index.
To solve this you can ignore non-alphabets by doing :
if(! isalpha(str[i]) {
str[j++] = str[i++]; // copy the char.
continue; // ignore rest of the loop.
}
This is going to break on any space characters (or anything else outside the range 'a'..'z') because you are accessing beyond the bounds of your hash array.
void striprepeatedchars(char *str)
{
int seen[UCHAR_MAX + 1];
char *c, *n;
memset(seen, 0, sizeof(seen));
c = n = str;
while (*n != '\0') {
if (!isalpha(*n) || !seen[(unsigned char) *n]) {
*c = *n;
seen[(unsigned char) *n]++;
c++;
}
n++;
}
*c = '\0';
}
This is code golf, right?
d(s){char*i=s,*o=s;for(;*i;++i)!memchr(s,*i,o-s)?*o++=*i:0;*o=0;}
...
// iterate through the input string char by char.
for(i=0,j=0;str[i];)
{
if (str[i] == ' ')
{
str[j++] = str[i++];
continue;
}
// if the char is not hashed.
if(!hash[str[i] - 'a'])
{
...
#include <stdio.h>
#include <string.h>
int hash[26] = {0};
static int in_valid_range (char c);
static int get_hash_code (char c);
static char *
remove_repeated_char (char *s)
{
size_t len = strlen (s);
size_t i, j = 0;
for (i = 0; i < len; ++i)
{
if (in_valid_range (s[i]))
{
int h = get_hash_code (s[i]);
if (!hash[h])
{
s[j++] = s[i];
hash[h] = 1;
}
}
else
{
s[j++] = s[i];
}
}
s[j] = 0;
return s;
}
int
main (int argc, char **argv)
{
printf ("%s\n", remove_repeated_char (argv[1]));
return 0;
}
static int
in_valid_range (char c)
{
return (c >= 'a' && c <= 'z');
}
static int
get_hash_code (char c)
{
return (int) (c - 'a');
}
char *s;
int i = 0;
for (i = 0; s[i]; i++)
{
int j;
int gap = 0;
for (j = i + 1; s[j]; j++)
{
if (gap > 0)
s[j] = s[j + gap];
if (!s[j])
break;
while (s[i] == s[j])
{
s[j] = s[j + gap + 1];
gap++;
}
}
}

Resources