I'm trying to write program that returns the index of the substring.
But if I have two strings like these:
(go-substring)
# ex. mango go man - go
"mango go man" is the main string in which we are finding "go", the substring.
I want the program to return 7 and not 4. I think the problem is is that it doesn't go through the entire string, but I don't understand why.
int findsub(const char *str1,const char *str2)
{
int l1=0,l2=0;
while(*(str1+l1)!='\0')
{
l1++;
}
while(*(str2+l2)!='\0')
{
l2++;
}
int i,j;
for(i=0,j=0;*(str1+i)!='\0'&&*(str2+j)!='\0';i++)
{
if(*(str1+i)==*(str2+j))
j++;
}
if(j==l2)
{
return i-j+1;
}
else
{
return 0;
}
}
You don't return counter j to 0 so after it saw first go in "mango" the condition of if it will not work any more
That code will solve your problem but you have another problem which is the algorithm will work if it found the characters of the second string even if it's separated
Try to put space between 'g' and 'o' and it will work, To find the whole word you will need to use nested loop
#include <stdio.h>
int findsub(const char *str1, const char *str2)
{
int l1 = 0, l2 = 0;
while (*(str1 + l1) != '\0')
{
l1++;
}
while (*(str2 + l2) != '\0')
{
l2++;
}
int i, j, x;
for (i = 0, j = 0; *(str1 + i) != '\0' && *(str2 + j) != '\0'; i++)
{
if (*(str1 + i) == *(str2 + j))
{
j++;
x = i;
}
if (j == l2 - 1)
{
j = 0;
}
}
return x + 1;
}
int main()
{
int num = findsub("mango go man", "go");
printf("%d\n", num);
}
Related
Sorry for such a mediocre question, but I ran into what seems to be a tiny problem, but simply can't get over it. For my task I have to take a line of string from a file, and put it into another file backwards, for example:
one two three
four five six
would be
three two one
six five four
My problem is, is that I'm getting
three two one
si five four
So basically the flaw is that there is a space character at the beginning of each line and the last letter of the last word is always missing. Here's my reverse function:
void reverse(char input[], int length, char output[]) {
char space = 32;
input[length - 1] = space;
int value = 0;
int i, k = 0, j;
for (i = 0; i <= length; i++) {
if (input[i] == space) {
for (j = i - 1; j >= k; j--, value++) {
output[value] = input[j];
}
if (j == -1) {
output[value] = space;
value++;
}
k = i;
}
}
char c = 0;
for (int i = 0, j = length - 1; i <= j; i++, j--) {
c = output[i];
output[i] = output[j];
output[j] = c;
}
}
What I'm doing is first reversing each word by character, and then the whole line. If someone could help me find the last bits that I've missed I would greatly appreciate it.
The flaws come from your approach:
why do you force a space at offset length - 1? If you read the line with fgets(), there is probably a newline ('\n') at the end of the line, but it might be missing at the end of the input, which would explain the x getting overwritten on the last line.
you should not modify the input buffer.
Here is a simplified version, along with a simple main function:
#include <stdio.h>
#include <string.h>
void reverse(const char *input, int length, char *output) {
int i, j, k, v;
for (i = k = v = 0;; i++) {
if (i == length || input[i] == ' ') {
for (j = i; j-- > k; v++) {
output[v] = input[j];
}
for (; i < length && input[i] == ' '; i++) {
output[v++] = ' ';
}
if (i == length) {
output[v] = '\0';
break;
}
k = i;
}
}
for (i = 0, j = length - 1; i < j; i++, j--) {
char c = output[i];
output[i] = output[j];
output[j] = c;
}
}
int main() {
char input[256];
char output[256];
while (fgets(input, sizeof input, stdin)) {
reverse(input, strcspn(input, "\n"), output);
puts(output);
}
return 0;
}
Output:
three two one
six five four
Here is a simpler reverse function that operates in one pass:
#include <string.h>
void reverse(const char *input, int length, char *output) {
int i, j, k, v;
for (i = k = 0, v = length;; i++) {
if (i == length || input[i] == ' ') {
for (j = i; j-- > k;) {
output[--v] = input[j];
for (; i < length && input[i] == ' '; i++) {
output[--v] = ' ';
}
if (v == 0) {
output[length] = '\0';
break;
}
k = i;
}
}
}
Replace input[length - 1] = space; with input[length] = space;
"Exercise 1-23. Write a program to remove all comments from a C program.
Don't forget to handle quoted strings and character constants
properly. C comments do not nest." K&R pg.34
Basically, I have two questions:
1)I'm completely new coding and I wanted to know if I'm at least thinking the problem the right way.
2)The code was built to ignore // till \n or /* till */. But whit the /* comment it always leaves one /.
Input: abc/*comment*/123
Output: abc/123
Input: abc/*123
Output: abc/
#include <stdio.h>
char s[1000]; //Principal array
int countS; //Number of char in array
int deletSingleLineComments(void);
int deletMultiLineComments(void);
int main(void){
int c;
while((c=getchar())!=EOF){
s[countS]=c;
++countS;
}
deletMultiLineComments(); //Function 1
deletSingleLineComments(); //Function 2
printf("\ns[]=\n%s\n\ncountS[]=%d\n",s,countS);
}
//Functions 1
int deletMultiLineComments(void){
char t[1000];
int i=0;
int inComment=0;
int diff=0;
int a,b,c;
while(i<=countS){
t[i]=s[i];
++i;
}
i=0;
while(i<=countS){
if(t[i]=='/' && t[i+1]=='*'){
inComment=1;
}
if(inComment==1){
++diff; //to equilibrate the number
}
if(inComment==0){
s[i-diff]=t[i];
}
if(t[i]=='*' && t[i+1]=='/'){
inComment=0;
}
++i;
}
s[i-diff+1]='\0';
countS=i-diff;
printf("\nt[]=\n%s\n",t);
}
//Function 2
int deletSingleLineComments(void){
int i=0;
char t[1000];
int inComment=0;
int diff=0;
while(i<=countS){
t[i]=s[i];
++i;
}
i=0;
while(i<=countS){
if(t[i] == '/' && t[i+1] == '/'){
inComment=1;
}
if(t[i]=='\n'){
inComment=0;
}
if(inComment==1){
++diff;
}
if(inComment==0){
s[i-diff]=t[i];
}
s[i-diff+1]='\0';
++i;
}
countS=i-diff;
}
Thank you.
while(i<=countS){ t[i]=s[i];... }
Note that character strings are zero based. For example "ABC" has length 3, it starts at zero index, and the last valid index is 2 (not 3). Therefore you should change the condition to i < string_length
while(i < countS){ t[i]=s[i];... }
Also be careful when accessing t[i+1], because while i is valid, i+1 can be out of bound.
if (i < (countS - 1))
if(t[i]=='/' && t[i+1]=='*')
In order to assign one string to another, you can introduce a second variable k, and increment k after each assignment. This method is easier (in my opinion) than using the diff variable and doing additions and subtractions.
In addition, rather than char t[1000];, you can use char *t = malloc(countS); to declare a temporary variable of length countS, then it has to be freed at the end with free(t). If your compiler supports variable length array, you can just put char t[countS].
Example:
char s[1000]; //Principal array
int countS; //Number of char in array
//Functions 1
void deletMultiLineComments(void)
{
char *t = malloc(countS);
int i = 0;
int k = 0;
int inComment = 0;
while (i < countS)
{
t[i] = s[i];
++i;
}
i = 0;
while (i < countS)
{
if (i < countS - 1)
if (t[i] == '/' && t[i + 1] == '*')
{
inComment = 1;
i+=2;
continue;
}
if (inComment == 1)
{
if (i < countS - 1)
if (t[i] == '*' && t[i + 1] == '/')
{
inComment = 0;
i+=2;
continue;
}
}
if (inComment == 0)
{
s[k] = t[i];
k++;
}
++i;
}
free(t);
s[k] = '\0';
countS = k;
printf("mulitline comment removed %s\n", s);
}
//Function 2
void deletSingleLineComments(void)
{
char *t = malloc(countS);
int i = 0;
int k = 0;
int inComment = 0;
while (i < countS)
{
t[i] = s[i];
++i;
}
i = 0;
while (i < countS)
{
if (i < countS - 1)
if (t[i] == '/' && t[i + 1] == '/')
{
inComment = 1;
i += 2;
continue;
}
if (t[i] == '\n')
{
inComment = 0;
}
if (inComment == 0)
{
s[k] = t[i];
k++;
}
i++;
}
free(t);
s[k] = '\0';
countS = k;
printf("single comment removed %s\n", s);
}
int main(void)
{
//get input
scanf("%s", s);
countS = 0;
while (s[countS]) countS++;
deletMultiLineComments(); //Function 1
deletSingleLineComments(); //Function 2
}
#include <stdio.h>
int main(void)
{
int i,j;
int wordstart = -1;
int wordend = -1;
char words[]= "this is a test";
char temp;
// Reverse each word
for (i = 0; i < strlen(words); ++i)
{
wordstart = -1;
wordend = -1;
if(words[i] != ' ')
wordstart = i;
for (j = wordstart; j < strlen(words); ++j)
{
if(words[j] == ' ')
{
wordend = j - 1;
break;
}
}
if(wordend == -1)
wordend = strlen(words);
for (j = wordstart ; j <= (wordend - wordstart) / 2; ++j)
{
temp = words[j];
words[j] = words[wordend - (j - wordstart)];
words[wordend - (j - wordstart)] = temp;
}
i = wordend;
printf("reversed string is %s:", words);
}
}
I tried in this way but i am getting this output:
siht is a test
my expected output is:
test a is this
I would appreciate if some one could come with a different approach for which time complexity is very less or correct me if it is the right approach. Thanks
Perhaps this belongs on the code review site instead?
Your approach seems very efficient to me (except that I would only call strlen(words) once and save the result in a register).
Two possible bugs look like:
wordend = strlen(words);
should be
wordend = strlen(words)-1;
and
for(j = wordstart ; j <= (wordend - wordstart) / 2 ; ++j) {
should be
for(j = wordstart ; j <= (wordend + wordstart) / 2 ; ++j) {
Final code looks like (with some extra {}):
#include <stdio.h>
int main(int argc,char *argv[])
{
int i,j;
char words[]= "this is a test";
int L=strlen(words);
// Reverse each word
for(i = 0; i < L; ++i) {
int wordstart = -1;
int wordend = -1;
if(words[i] != ' ')
{
wordstart = i;
for(j = wordstart; j < L; ++j) {
if(words[j] == ' ') {
wordend = j - 1;
break;
}
}
if(wordend == -1)
wordend = L-1;
for(j = wordstart ; j <= (wordend + wordstart) / 2 ; ++j) {
char temp = words[j];
words[j] = words[wordend - (j - wordstart)];
words[wordend - (j - wordstart)] = temp;
}
i = wordend;
}
}
printf("reversed string is %s:",words);
return 0;
}
You can create a double linked list as a base data structure. Then, iterate through the words and insert them in the list as you find them.
When you reach the end of the sentence, simply traverse the list backwards and print the words as you go through them
Simply we can just use a n*1 2D character array tailored to suit our needs!!!
#include <stdlib.h>
int main()
{
char s[20][20];
int i=0, length=-1;
for(i=0;;i++)
{
scanf("%s",s[i]);
length++;
if(getchar()=='\n')
break;
}
for(i=length;i>=0;i--)
printf("%s ",s[i]);
return 0;
}
Start tokenizing the line from the last character and continue to the first character. Keep one pointer anchored at the base of the current word, and another pointed which will decrease while a word start is not found. When you find a word start while scanning like this, print from the word start pointer to the word end anchor. Update the word end anchor to the previous character of the current word start char.
You might want to skip the blankspace characters while scanning.
UPDATE
This is a quick implementation:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define MAX_BUF 256
void show_string (char *str, int i, int n)
{
while (i <= n)
{
printf ("%c", str[i]);
i++;
}
}
int main (void)
{
char str[MAX_BUF];
int end_anchor, start_ptr;
int state;
printf ("\nEnter a string: ");
scanf (" %[^\n]", str);
start_ptr = strlen (str) - 1;
end_anchor = start_ptr;
state = 0;
while (start_ptr >= -1)
{
switch (state)
{
case 0:
if ((!isspace (str[start_ptr]) && (start_ptr >= 0)))
{
start_ptr--;
}
else
{
state = 1;
}
break;
case 1:
show_string (str, start_ptr + 1, end_anchor);
state = 2;
start_ptr--;
printf (" ");
break;
case 2:
if (!isspace (str[start_ptr]))
{
state = 0;
end_anchor = start_ptr;
}
else
{
start_ptr--;
}
break;
}
}
printf ("\n");
return 0;
}
The end_anchor points to each end word, and the start_ptr finds the start of the word of which the end is held by end_anchor. When we find a word start (by blankspace characters or start_ptr = -1), we print all the characters from start_ptr + 1 to end_anchor. The + 1 is because of the implementation: start_ptr points to the blankspace character, and the print routine will print all the characters from i to n. Once we have detected one blank space we print it and we skip adjacent blankspaces (in case 2) and preserve only one which is manually printed. Once a non blankspace is detected, we have got another word end, for which we set the end_anchor to this index in the case 2, and set state = 0 , so that we can search for the word start again.
if(words[i] != ' ')
wordstart = i;
This statement what about the else part? if words[i] == ' ', and wordstart remains -1.
So maybe try to use:
while (words[i] && words[i] == ' ') ++i;
if (!words[i])
break;
wordstart = i;
Then you should output the result out of the i loop.
Finally, if you want to get the result you expected, you should reverse the whole sentence once more, with the way you used in the loop.
I would use write function similar to strrchr for finding last occurence of ' ', if its found print word that follows, rewrite this ' ' with '\0' and repeat it in loop till no more words are found. At the end I would print the content of this string again because there is most likely no ' ' before the first word.
I would write own function instead of strrchr because strrchr calculates the lenght of the given string, which is redundant in this case. This length doesn't have to be calculated more than once.
Here's the code:
char* findLastWord(char* str, int* len)
{
int i;
for (i = *len - 1; i >= 0; --i)
{
if (str[i] == ' ')
{
str[i] = '\0';
if (i < *len - 1)
{
*len = i - 1;
return &str[i + 1];
}
}
}
return NULL;
}
int main (int argc, char *argv[])
{
char str[] = " one two three four five six ";
int len = strlen(str);
char* lastWord = findLastWord(str, &len);
while (lastWord != NULL)
{
printf("%s\n", lastWord);
lastWord = findLastWord(str, &len);
}
if (len > 1)
printf("%s\n", str);
return 0;
}
output:
six
five
four
three
two
one
Hope this helps ;)
#include<stdio.h>
#include<string.h>
void reverse(char *str, size_t len)
{
char tmp;
size_t beg, end;
if (len <=1) return;
for (beg=0,end=len; beg < --end ; beg++) {
tmp = str[beg];
str[beg] = str[end];
str[end] = tmp;
}
}
int main(void)
{
char sentence[] = "one two three four five";
size_t pos, len;
printf("Before:%s\n",sentence);
for (pos = len= 0; sentence[pos]; pos += len) {
pos += strspn( sentence+pos, " \t\n" );
len = strcspn( sentence+pos, " \t\n" );
reverse ( sentence + pos, len );
}
reverse ( sentence , pos );
printf("After:%s\n",sentence);
return 0;
}
#include <iostream>
#include <string>
using namespace std;
char* stringrev(char s[], int len)
{
char *s1 = (char*)malloc(len+1);
int i=0;
while (len>0)
{
s1[i++] = s[--len];
}
s1[i++] = '\0';
return s1;
}
void sentrev(char s[], int len)
{
int i=0; int j=0;
char *r = (char*)malloc(len+1);
while(1)
{
if(s[j] == ' ' || s[j] == '\0')
{
r = stringrev(s+i, j-i);
i = j+1;
cout<<r<<" ";
}
if (s[j] == '\0')
break;
j++;
}
}
int main()
{
char *s = "this is a test";
char *r = NULL;
int len = strlen(s);
cout<<len<<endl;
r = stringrev(s, len);
cout<<r<<endl;
sentrev(r, len);
return 0;
}
The above code snap reverse the sentence, using char *r
and printing cout<
#include<stdio.h>
#include<conio.h>
#include<string.h>
int main()
{
char st[50], rst[50];
printf("Enter the sentence...\n");
gets(st);
int len=strlen(st), p;
int j=-1,k;
p=len;
for(int i=(len-1); i>=0; i--)
{
//searching for space or beginning
if(st[i]==' ')
{
//reversing and storing each word except the first word
for(k=i+1;k<p;k++)
{
//printf("%c",st[k]);
rst[++j]=st[k];
}
j++;
rst[j]=' ';
printf("\n");
p=i;
}
else if(i==0)
{
//for first word
for(k=i;k<p;k++)
{
//printf("%c",st[k]);
rst[++j]=st[k];
}
}
}
printf("Now reversing the sentence...\n");
puts(rst);
return 0;
}
Use a main for loop to traverse till the end of the sentence:
Copy the letters in a string until you find a space.
now call add#beginning function and in that function add the string each time you pass a string to the linked list.
print the contents of the linked list with a space inbetween to get the expected output
My code,just traverse from the last and if you find a space print the characters before it,now change the end to space-1;This will print till the second word,finally just print the first word using a single for loop.Comment for alter approach.
Program:
#include<stdio.h>
int main()
{
char str[200];
int i,j,k;
scanf("%[^\n]s",&str);
for(i=0;str[i]!='\0';i++);
i=i-1;
for(j=i;j>=0;j--)
{
if((str[j])==' ')
{
for(k=j+1;k<=i;k++)
{
printf("%c",str[k]);
}
i=j-1;
printf(" ");
}
}
for(k=0;k<=i;k++)
{
printf("%c",str[k]);
}
}
using stack
#include <iostream>
#include <stdio.h>
#include <stack>
int main()
{
std::stack<string> st;
char *words= "this is a test";
char * temp = (char *)calloc(1, sizeof(*temp));
int size1= strlen(words);
int k2=0;
int k3=0;
for(int i=0;i<=size1;i++)
{
temp[k2] = words[i];
k2++;
if(words[i] == ' ')
{
k3++;
if(k3==1)
temp[k2-1]='\0';
temp[k2]='\0';
st.push(temp);
k2=0;
}
if(words[i] == '\0')
{
temp[k2]='\0';
st.push(temp);
k2=0;
break;
}
}
while (!st.empty())
{
printf("%s",st.top().c_str());
st.pop();
}
I am trying to make "Hello World" to "World Hello".
But the code is not working properly the way I wanted it to behave.
See the code below:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct llnode
{
char *info;
struct llnode *next;
};
typedef struct llnode NODE;
int main()
{
char msg[50],word[10],*str;
int i=0,length=0,j=0;
NODE *ptr,*front=NULL,*temp,*last=NULL;
//printf("Enter the sentence: ");
str= "Hello World"; //fgets(msg,sizeof(msg),stdin);
while(str[i]!='\0')
{
if((str[i]==' ')||(str[i]=='\n'))
{
word[j]='\0';
j=0;
ptr=(NODE *)malloc(sizeof(NODE));
ptr->info=word;
ptr->next=NULL;
if(front==NULL)
{
front=ptr; // only change the value of front here;
}
else
{
temp=front;
while((temp->next)!=NULL)
{
temp=temp->next;
}
temp->next=ptr;
}
printf("\n##%s\n",front->info); // prints thewords and not
//the first word
}
else
{
word[j]=str[i];
j++;
}
i++;
}
temp=front;
while(temp)
{
length++;
printf("%s ",temp->info);
temp=temp->next;
}
printf("\nLength of Linked List(or, number of words): %d\n",length);
i=0;
printf("\n************************\n");
while(i<length)
{
temp=front;
while(temp->next!=last)
{
temp=temp->next;
}
last=temp;
printf("%s ",temp->info);
i++;
}
return 0;
}
Thanks
There are a number of things wrong with the code:
You are using a single word array to read all the words. So, when you read "Hello", you read into the word array, print "##Hello" and store the pointer to the word array as front->info. Then, you OVERWRITE the word array with World. Also, please note that you NEVER add a node with the word "World" because you exit the loop as soon as you encounter the '\0'. So, your linked list contains only one node. But, there is a problem, since you stored a pointer to the word array in the first node and since the word array has been overwritten with "World", when you exit the loop, there is only one node in the list and the info of this node is word array which contains "World" and not "Hello" like it once did. So, I guess this explains the output?
You should be able to use strtok() for this purpose. See this example, just replace the hashtags with spaces and print backwards. This is by far the easiest way to accomplish this.
Looks like homework... but, for starters, if your delimiters are a space and a newline:
if((str[i]==' ')||(str[i]=='\n'))
...then a string that doesn't contain a space or a newline at the end will never parse the last element:
str= "Hello World"; //fgets(msg,sizeof(msg),stdin);
...so my guess is that you're never even putting "World" into the linked list.
Finally I did this one
/**
I am a boy -> boy a am I
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int i, j, n, temp, temp_i, cnt;
//char *array = "Samsung";
char array[1000];
char newarr[strlen(array)];
printf("Enter The String: \n");
gets(array);
for(i = (strlen(array)-1), n = 0, j = 0; i >= 0; i--)
{
if( array[i] != ' ')
{
n++;
}
else
{
temp = n;
temp_i = i;
for(n = 0; n <= temp; n++)
{
// i = i + 1;
newarr[j++] = array[i++];
}
i = temp_i;
n = 0;
}
if(i == 0)
{
newarr[j++] = ' ';
temp = n;
temp_i = i;
for(n = 0; n <= temp; n++)
{
// i = i + 1;
newarr[j++] = array[i++];
}
i = temp_i;
n = 0;
}
//newarr[j++] = array[i];
}
newarr[j] = '\0';
cnt = 0;
for(j = 0; j <= (strlen(newarr)-1); j++)/*This is not required just do some R n D*/
{
newarr[j] = newarr[++cnt];
}
// printf("The first element is %c \n", newarr[1]);
puts(newarr);
return 0;
}
Here is one solution with c++11 . Which reverses the words as required and prints it on screen.
vector<string> words;
string str = "hello world c++11";
size_t current = 0;
size_t found = str.find(" ");
while(found != string::npos)
{
words.push_back(str.substr(current, found - current));
current = found + 1;
found = str.find(" ",current);
}
words.push_back(str.substr(current));
std::ostream_iterator<string> Display_iter(std::cout," ") ;
std::copy(words.rbegin(), words.rend(), Display_iter);
1) First reverse the entire string ( it gives like "dlrow olleh")
2) and then call/reverse word from first character until space/endOfString encounters.
3) It gives desired output.
#include
#include
int main() {
char *src = "I am a boy";
char dest[50][50];
int idx = 0;
int priv_idx = 0;
int i = 0;
int j = 0;
while(src[i] != '\0') {
if(src[i] == ' ') {
if(priv_idx == idx) {
idx ++;
j = 0;
}
i++;
continue;
}
*(*(dest + idx) + j) = src[i];
i++;
j++;
priv_idx = idx;
}
for (i = idx; i>=0; --i) {
printf("%s\n\r",dest[i]);
}
return 0;
}
#include <stdio.h>
#include <string.h>
#define MAX_ROW 50
#define MAX_COLUMN 50
char dest[MAX_ROW][MAX_COLUMN];
int str_rev_order(char *src)
{
int idx = 0;
int priv_idx = 0;
int i = 0;
int j = 0;
for(i = 0;i<MAX_ROW; ++i) {
memset(dest[i],0,MAX_COLUMN);
}
/* reset the counter */
i = 0;
while(src[i] != '\0') {
if(idx >= MAX_ROW-1) {
printf("Don't support more than %d substring.\n\r",MAX_ROW);
return -1;
}
if(j >= MAX_COLUMN -1) {
printf("Don't support string length more than %d.\n\r",MAX_COLUMN);
return -1;
}
if(src[i] == ' ') {
if(priv_idx == idx) {
/* going to next row & reset the column counter*/
idx ++;
j = 0;
}
i++;
continue;
}
*(*(dest + idx) + j) = src[i];
i++;
j++;
priv_idx = idx;
}
return idx;
}
void print_rev_order(int idx) {
int i;
for (i = idx; i>=0; --i) {
printf("%s\n\r",dest[i]);
}
}
int main() {
char *src = "I am a boy";
int idx = str_rev_order(src);
print_rev_order(idx);
return 0;
}
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++;
}
}
}