My sister and I recently got an assignment in C to write a function which finds a specific word in a string, and if found, returns the first letter index of that word found in the string. But all sorts of problems popped up...
Main File [testing_word_search.c]
#include <stdio.h>
#include "u_s_search_word_in_string.h"
int main()
{
int first_letter_idx = 0;
char line[32] = "Janen is a dog";
char word[4] = "dog";
first_letter_idx = search_word_in_string( line, word );
printf("\nThe beginning of the word is at index %d.\n", first_letter_idx );
return 0;
};
Functions [u_s_search_word_in_string.c]
#include <stdio.h>
#include "u_s_search_word_in_string.h"
int search_word_in_string ( char line[], /* ( Input ) */
char word[] /* ( Input ) Word to search for in {line}. )
{
int line_idx = 1;
int word_idx = 1;
int first_letter_idx = 0;
/* Finding word. */
while ( (line[line_idx] != '\0') )
{
if ( (line[line_idx] = word[word_idx]) && (word[word_idx] != '\0') )
{
/* Index of beginning letter of word set to another variable. */
if ( (first_letter_idx = 0) )
{
first_letter_idx = line_idx;
}
line_idx++;
word_idx++;
}
else
{
/* If word turns out to be not found, continue. */
first_letter_idx = 0;
line_idx++;
word_idx++;
};
};
if ( (first_letter_idx = 0) )
{
puts("Cannot find word in string.");
return -1;
};
if ( first_letter_idx >= 1 )
{
puts("Found word, returning first letter index.");
};
return (first_letter_idx);
};
Function's header file. [u_s_search_word_in_string.h]
int search_word_in_string ( char line[], /* ( Input ) */
char word[] /* ( Input ) Word to search for in {line}. */ );
Sorry if the comments may seem crappy, I will work on them later, but I don't know what is wrong...
First of all, when compiling there isn't a warning about using Puts(), second, the compile tells me everything was successful but when I execute it, this happens:
./geany_run_script.sh: 5: ./geany_run_script.sh: ./testing_word_search: not found
My inputed build command:
Compile: gcc -Wall -c testing_word_search.c
u_s_search_word_in_string.c Build: gcc -o word_search
testing_word_search.o u_s_search_word_in_string.o Execute: "./%e"
Usual default setting, I know that if I want to run a program I must go to the main module.
And when I run it using the terminal, it says this:
The beginning of the word is at index 0.
There should be another message other then this technically.
I would really be thankful if one of you members points out my mistake, because so far, I am clueless as to what I might be doing wrong.
Some issues with your code:
You don't need semicolons after a block of statements (i.e. after the closing bracket }).
You have to compare your chars via == and not via = (first is a comparison, second is an assignment).
line_idx and word_idx should be zero (because the string you are looking for can also exist at the beginning).
first_letter_idx should default to -1 (because, again, 0 is a valid value), and you should check for -1 and not for 0 to know if the search failed.
The rest seems okay, but you can shorten your code a bit (e.g. the check word[word_idx] != '\0' is unnecessary; also line_idx++; and word_idx++; can be written beneath the if-else statement, because they get executed no matter what happens.)
I hope this solves most of your problems.
The header string.h provides a function strstr that is tailor made for what you are trying to accomplish. Full example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *string = NULL;
char *substr = NULL;
char *p = NULL;
printf ("\nEnter string : ");
scanf ("%m[^\n]%*c", &string);
printf ("\nEnter substr : ");
scanf ("%m[^\n]%*c", &substr);
if ((p = strstr (string, substr)) != NULL)
printf ("\nSubstring found beginning at : %c (char '%lu' in string)\n\n",
*p, p - string + 1);
else
printf ("\nSubstring NOT in string.\n\n");
if (string) free (string);
if (substr) free (substr);
return 0;
}
output:
$ ./bin/strstrc
Enter string : Janen is a dog
Enter substr : dog
Substring found beginning at : d (char '12' in string)
If you must do it without using strstr, then the link in the comment will help.
Check the below code:
#include <stdio.h>
#include<string.h>
int search_word_in_string ( char line[], /* ( Input ) */
char word[] )
{
int line_idx = 0;
int k;
int word_idx = 0;
int first_letter_idx = 0;
/* Finding word. */
while ( (line[line_idx] != '\0') )
{
word_idx =0;
if(line[line_idx] == word[word_idx])
{
k = line_idx;
while(word[word_idx] != '\0' && word[word_idx] == line[k])
{
k++;
word_idx++;
}
if((k-line_idx) == strlen(word))
return line_idx+1;
}
line_idx++;
}
return -1;
}
int main()
{
int first_letter_idx = 0;
char line[32] = "Janen is a dog";
char word[4] = "is";
first_letter_idx = search_word_in_string( line, word );
if(first_letter_idx > -1)
printf("\nThe beginning of the word is at index %d.\n", first_letter_idx );
else
printf("\n String not found \n");
return 0;
}
Well thank you Philipp and Bluepixy, I updated my code:
/*
* Author: Usia, Sebastian
* Date: 21/NOV/2014
*
* Input: Two character type variables.
* Output: Index number of beginning letter of word.
*
* Description: Uses an algorithm to find a word in a string and if found
* it returns the index number of the first letter of the found word.
*
*/
#include <stdio.h>
#include "u_s_search_word_in_string.h"
int search_word_in_string ( char line[], /* ( Input ) */
char word[] /* ( Input ) Word to search for in {line}. */ )
{
int line_idx = 0;
int word_idx = 0;
int first_letter_idx = 0;
int word_length = 0;
int matched = 0; /* Number of consecutive characters matching between {word} and {line}. */
/* Find {word}'s length. */
while (word [word_length] != '\0') word_length++;
printf("word length is %d\n", word_length);
/* Finding word. */
while ( (line[line_idx] != '\0') && (matched != word_length) )
{
printf("before IF: line_idx = %d, word_idx = %d\n", line_idx, word_idx);
if ( (word[word_idx] != '\0') && (line[line_idx] == word[word_idx]) )
{
printf("*match* line_idx = %d, word_idx = %d\n", line_idx, word_idx);
/* Marking {word}'s first letter in the text line. */
if ( (word_idx == 0) )
{
first_letter_idx = line_idx;
}
matched++;
word_idx++;
}
else
{
printf("letters do not match --- line_idx = %d, word_idx = %d\n",line_idx, word_idx);
/* If letters don't match, reset word_idx and match counter. */
word_idx = 0;
matched = 0;
};
line_idx++; /* No matter what we move ahead the {line_idx}. */
};
printf("matched %d\n", matched );
if ( matched == word_length )
{
printf("Found word, returning first letter index.");
return (first_letter_idx);
}
else
{
printf("Cannot find word in string.");
return -1;
};
};
Added traces just to be sure.
I never really heard of "strstr" before, I will check it out sometime soon. Thanks again.
Related
I have a problem I am trying to solve. I have an array of string and integers and I want to convert only the integers(163) to actual integers in C.
I have managed to locate my desired numbers (163) array location but i am unsure how to convert them to numbers. I have tried to use strtol, atoi and strtoumax but I havent been succesful.
I have added my code below.
char busy[30] = {"this is; it was; 163; 234;;"};
int tag = 0;
int location = 0;
for (int i = sizeof(busy); i > 0; i--) {
printf("%c\n", busy[i]);
if (busy[i] == ';') {
tag = tag+1;
printf("tag is %i \n", tag);
}
if (tag == 4) {
printf("for loop is %i\n", i);
location = i;
break;
}
}
location = location+1;
int loca_saved = 0;
int loca_finish = 0;
int tag1 = 0;
while (busy[location] != ';') {
if (busy[location] == ' ' && busy[location - 1] == ';') {
//printf("not printing whitespace between semicolon and characters\n");
location++;
}
else {
if (tag1 == 0) {
tag1 = tag1+1;
loca_saved = location; //this is to tell me the array location for the first char
}
if (busy[location + 1] == ';') {
loca_finish = location; //this is to tell me the array location for the last char
}
putchar(busy[location]); //this is to print my desired characters(163)
location++;
}
}
strspn and strcspn can be used to parse a string.
Instead of sscanf, strtol could be used to get the number.
#include <stdio.h>
#include <string.h>
int main ( void) {
char busy[] = "this is; it was; 163; 234;";
char *dlm = "0123456789";
char *parse = busy;
int number = 0;
while ( *parse) {
parse += strcspn ( parse, dlm);//count to next delimiter
if ( 1 == sscanf ( parse, "%d", &number)) {
printf ( "%d\n", number);
}
parse += strspn ( parse, dlm);//skip delimeters
}
return 0;
}
Parsing could also work off the semicolon.
Some fields will not have an integer.
#include <stdio.h>
#include <string.h>
int main ( void) {
char busy[] = "this is; it was; 163; 234;";
char *dlm = ";";
char *parse = busy;
int number = 0;
while ( *parse) {
if ( 1 == sscanf ( parse, "%d", &number)) {
printf ( "%d\n", number);
}
else {
printf ( "could not parse integer\n");
}
parse += strcspn ( parse, dlm);//count to next delimiter
parse += strspn ( parse, dlm);//skip delimeters
//the above line will skip all consecutive delimiters
//to process each delimiter use the line below
//++parse;//skip one delimiter
}
return 0;
}
Since you have a modifiable string you can use strtok to separate it into substrings based on the ; delimiter. This code does that in in case a substring is a number, it gets printed.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (void)
{
char str[30] = {"this is; it was; 163; 234;;"};
for(char* p=strtok(str, ";"); p!=NULL; p=strtok(NULL,str))
{
char* endptr;
int i = strtol(p,&endptr,10);
if(endptr != p)
{
printf("%d\n", i);
}
}
}
Output:
163
234
strtol sets the "endptr" parameter to point at the beginning of the string in case it fails, so we can use that to determine if a substring was a number or not.
It all depends on the exact grammar that you would like to parse. Note, for example, that negative integers start with a - character, and that there has to be a maximum integer value. Since you are working quite "low level", you may want to perform the conversion to an integer while you are reading the string, e.g.:
#include <ctype.h>
#include <stdio.h>
int main(void)
{
char busy[30] = {"this is; it was; 163; 234;;"};
for (char *p = busy; *p; ++p) // Loop over the string
if (isdigit(*p)) // Found first digit of an unsigned integer
{
unsigned n = (unsigned) (*p - '0'); // Store the value of the first digit in 'n'
// While reading the number, shift the digits to the appropriate positions
while (isdigit(*++p))
n = n * 10U + (unsigned) (*p - '0');
printf("%u\n", n); // We have finished parsing the integer, print it
}
}
Using atoi can also work, but it will require two passes over each integer: one in atoi itself and another one to move past the integer in the string you're parsing.
The function strtol allows you to pass a pointer to your pointer which is set to one place after the read integer, which avoids the issue. You can use this to advance the pointer. In this code example, the pointer is either advanced manually or by strtol:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char busy[30] = {"this is; it was; 163; 234;;"};
for (char *p = busy; *p; )
if (isdigit(*p))
printf("%ld\n", strtol(p, &p, 10));
else
++p;
}
Another alternative, without the use of isdigit:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char busy[30] = {"this is; it was; 163; 234;;"};
for (char *p = busy; *p; )
{
char *end;
long n = strtol(p, &end, 10);
if (p != end) // Pointer was advanced, so an integer was read
{
printf("%ld\n", n);
p = end;
}
else // Pointer was not advanced, do so manually
++p;
}
}
I am tring to make a function from exercise in book "Programming in C". The correct function should indicate if a line contain some word, if yes - return its first charcter position(of the word) in the line.
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
int substring (char a[], char b[]);
int main ()
{
char line1[15], line2[15];
printf("Print first one\n");
int i = 0;
char character;
do
{
character = getchar ();
line1[i] = character;
i++;
}
while (character != '\n');
line1[i-1] = '\0';
printf ("Print the second one\n");
scanf("%s", line2);
printf("%s, %s\n", line1, line2); \\ for checking lines
int index;
index = substring (line1, line2);
printf("The result is: %i\n", index);
}
int substring (char a[], char b[])\*function to determine if a line contains a word, if yes then return its polition, else return -3*\
{
int len1 = strlen(a), len2 = strlen(b);
int current1 = 0, current2 = 0;
bool found = false;
int result;
while( current1 < len1 )
{
if (a[current1] == b[current2])
{
if(!found)
{
result = current1+1;
}
else
found = true;
while ((a[current1] == b[current2]) && (a[current1] != '\0') && (b[current2] != '\0'))
{
current1++;
if(current2+1 == len2)
return result;
current2++;
}
current1 = result;
}
else
{
current2 = 0;
found = false;
current1++;
}
}
return -3;
}
The problem is somehow in the second function(substring), cause when i try to search for "word" in line "Here is your word", fucntion works properly, but when i try to search "word" in a line "Here is your wwwwword", function returns -3 (which is indication if something went wrong).
For starters there is the standard C string function strstr that allows to determine whether one string is contained in other string.
If you need to write such a function yourself then your function implementation looks too complicated.
For example the if-else statement
if (a[current1] == b[current2])
{
if(!found)
{
result = current1+1;
}
else
found = true;
// ...
does not make a great sense at least by two reasons. The first one is the variable result that can be returned from the function in the while loop does not contain the exact index of the found word. And the second one is that found never can be equal to true within the function. So the condition in the if statement
if( !found )
always evaluates to true.
Also you forgot to reset the variable current2 in the compound statement of the if statement after the while loop.
Apart from this the function parameters should have the qualifier const because passed strings are not being changed in the function. And the function return type shall be size_t.
The function can look for example the following way as it is shown in the demonstrative program below.
#include <stdbool.h>
#include <string.h>
size_t substring( const char *s1, const char *s2 )
{
size_t n1 = strlen( s1 );
size_t n2 = strlen( s2 );
size_t i = 0;
bool found = false;
if (!( n1 < n2 ))
{
for ( size_t n = n1 - n2; !found && i <= n; i += !found )
{
size_t j = 0;
while (s2[j] != '\0' && s2[j] == s1[i + j]) ++j;
found = s2[j] == '\0';
}
}
return found ? i : -1;
}
int main( void )
{
const char *word = "word";
const char *s1 = "Here is your word";
const char *s2 = "Here is your wwwwword";
printf( "%zu\n", substring( s1, word ) );
printf( "%zu\n", substring( s2, word ) );
}
The program output is
13
17
If a word is not found in the source string then the function returns a value of the type size_t that is equal to -1.
Pay attention to that the variable character should be declared having the type int instead of char. Otherwise in general the comparison with EOF can produce unexpected result if the type char behaves as the type unsigned char.
As the title mention, I want to check if a substring is found or not into another string.
#include <stdio.h>
#include <stdlib.h>
int isIncluded(char *text, char* pattern);
int main()
{
char text[30];
char pattern[30]; int result;
printf(" Please introduce your text \n");
scanf("%s", &text);
printf(" Please introduce the pattern you are looking for \n");
scanf("%s", &pattern);
result = isIncluded( &text, &pattern);
if ( result == 1)
{
printf(" Your pattern has been found in your text \n " ) ;
}
if ( result == 0)
{
printf(" no substring found \n " ) ;
}
}
int isIncluded(char *text, char* pattern)
{
int ct = 0;
int numberofcharacters = 0;
while ( *pattern != '\0')
{
pattern++;
numberofcharacters++;
}
while ( *text != '\0' && pattern != '\0')
{
if ( *pattern == *text)
{
pattern++;
ct++;
text++;
}
else
{
text++;
}
}
if ( ct == numberofcharacters )
{
return(1);
}
else
{
return(0);
}
}
The idea is to compare the first character of the text variable with the pattern variable, lets take an example:
Suppose we have "TEXT" in text variable and "EX" in pattern:
I start to compare T with E, in this case, no match.
I point at E and compare again, there is a match.
Because of the match, I point at X in pattern and do the same in text, and I do another test.
2nd match,therefore, the number of characters in the pattern variable will be the same as the ct variable, which counts only when there is a match.
Therefore the return should be equal to 1.
The code returns always zero. I dont understand why ?
#include <stdio.h>
#include <stdlib.h>
int isIncluded(char *text, char* pattern);
int main()
{
char text[30];
char pattern[30]; int result;
printf(" Please introduce your text \n");
scanf("%s", text);
printf(" Please introduce the pattern you are looking for \n");
scanf("%s", pattern);
result = isIncluded( text, pattern);
if ( result == 1)
{
printf(" Your pattern has been found in your text \n " ) ;
}
if ( result == 0)
{
printf(" no substring found \n " ) ;
}
}
int isIncluded(char *text, char* pattern)
{
char *tempPattern = pattern;
int ct = 0;
int numberofcharacters = 0;
while ( *tempPattern != '\0')
{
tempPattern++;
numberofcharacters++;
}
while ( *text != '\0' && pattern != '\0')
{
if ( *pattern == *text)
{
pattern++;
ct++;
text++;
}
else
{
text++;
}
}
if ( ct == numberofcharacters )
{
return(1);
}
else
{
return(0);
}
}
It was the first loop that was problematic, because, as mentionned in the comment section, it completely changed the variable pattern to nothing, therefore there was nothing to compare to. This code works fine.
assuming this is a homework problem or you are learning consider this revision for starters:
int isIncluded ( char *text, char *pattern ); /* this is ok */
/*
can also write it this way
int isIncluded ( char text[], char pattern[] );
*/
int main ( void )
{
char text[30];
char pattern[30];
int result;
printf(" Please introduce your text \n");
scanf("%s", text); /* don't use &text here */
printf(" Please introduce the pattern you are looking for \n");
scanf("%s", pattern); /* don't use &pattern here */
/* don't pass a pointer to a pointer, the strings text and pattern are already pointers, you passing &text would mean isIncluded( char **text ) */
result = isIncluded( text, pattern );
if ( result == 1 )
{
printf(" Your pattern has been found in your text \n " ) ;
}
else if ( result == 0 )
{
printf(" no substring found \n " ) ;
}
else
{
/* don't overlook possibilities of missing simple stuff by not making use of else with if statements */
printf(" Error: value of result is %d\n", result );
}
}
I haven't looked into why isIncluded is always returning zero, but passing a pointer to a pointer to it was not helping.
If you are nice maybe I'll write partial code to get u started,
but what you are wanting to do is already completely accomplished by strstr() provided by # include <string.h>
also, defining char text[30] is the same a defining a pointer to type char called text but in addition it reserves space in memory to hold [n] characters which you said to be 30. It may be helpful in this case to understand the difference between defining and declaring in addition to what is actually happening when doing text[3] versus *(text+3) both of which are valid, unambiguous, and do the same thing.
In your isIncluded function first for calculating the length of pattern you change pattern and then was not the first one, you can calculate length with some other way like strlen but if you want to calculate with this way you should create a new variable as temp and change temp variable.
Another problem in this function in condition of end of pattern in second while loop should use *pattern != '\0' instead of pattern != '\0'
and when you want to call a function whit char* argument and you have array of character you should send array and &text type is char**
and in end here what you want:
#include <stdio.h>
#include <stdlib.h>
int isIncluded(char *text, char* pattern);
int main()
{
char text[30];
char pattern[30]; int result;
printf(" Please introduce your text \n");
scanf("%s", &text);
printf(" Please introduce the pattern you are looking for \n");
scanf("%s", &pattern);
result = isIncluded(text, pattern);
if (result == 1)
{
printf(" Your pattern has been found in your text \n ");
}
if (result == 0)
{
printf(" no substring found \n ");
}
}
int isIncluded(char *text, char* pattern)
{
int ct = 0;
int numberofcharacters = 0;
char *temp = pattern; //<- define new variable
while (*temp != '\0')
{
temp++;
numberofcharacters++;
}
while (*text != '\0' && *pattern != '\0')
{
if (*pattern == *text)
{
pattern++;
ct++;
text++;
}
else
{
text++;
}
}
if (ct == numberofcharacters)
{
return(1);
}
else
{
return(0);
}
}
I'm trying to convert a string from upper case to lower case to check if it is a palindrome, however I keep getting the error:
"function declaration is not a prototype"
I already added #include <string.h> in the header, but it still doesn't work. How do I get around this issue?
This is the code:
int main (void)
{
char *user_string, *user_string_rev;
/* the malloc function is used to make sure that enough memory is allocated for the string and that it does not overwrite memory boxes of other variables. */
user_string= (char*)malloc(BUFF_SIZE*sizeof(char));
user_string_rev= (char*)malloc(BUFF_SIZE*sizeof(char));
printf("Please enter a string:");
fgets(user_string,BUFF_SIZE, stdin); /* fgets function take the string the user inputs and stores it into user_string. */
user_string_rev=strcpy(user_string_rev, user_string); /*the strcpy takes the string the user inputs and copies it to user_string_rev. */
strlwr(user_string_rev);
palindrome_check(user_string,user_string_rev); /*this is the palindrome function used to check if the two strings are palindromes, it intakes two arguments, the two strings and does not return anything. */
return 0;
}
Replace :
strlwr(user_string_rev);
which is not a standard function with:
int i = 0;
while (user_string_rev[i])
{
if (isalpha(user_string_rev[i]))
user_string_rev[i] |= 32;
++i;
}
Don't forget to add the ctype header at the top of your .c file to use isalpha:
#include <ctype.h>
the following proposed code:
incorporates the comments to the question
cleanly compiles
properly checks for errors
will treat a string that is nothing but a newline as NOT a palindrome
And now the proposed code:
#include <stdio.h> // getline(), printf()
#include <stdlib.h> // free()
#include <ctype.h> // tolower()
#include <string.h> // strlen(), strchr()
// prototypes
void palindrome( char *, size_t length );
int main( void )
{
char *inputStr = NULL;
size_t lengthStr = 0;
printf("Please enter a string:");
if( -1 != getline( &inputStr, &lengthStr, stdin ) )
{
size_t length = strlen( inputStr );
for( size_t i = 0; i < length; i++ )
{
inputStr[i] = (char)tolower( inputStr[i] );
}
char *newline = strchr( inputStr, '\n' );
if( newline )
{
*newline = '\0';
length--;
}
palindrome( inputStr, length );
}
free( inputStr );
return 0;
}
void palindrome( char stringToCheck[], size_t length )
{
size_t index = length - 1; // don't check NUL terminator byte
size_t i;
for( i = 0; i < index; i++ )
{
if( stringToCheck[i] != stringToCheck[ index ] )
{
break;
}
index--;
}
if( i < index )
{
printf( "%s is not a palindrome\n", stringToCheck );
}
else
{
printf( "%s is a palindrome\n", stringToCheck );
}
}
I'm trying to make a method called "censor" that finds the 4 letter words in a string using 2 methods ive already made, the new method has to void censor(*start), an explanation as to what I'm doing wrong would be great, thanks!
void four_stars(char *start){
int count = 0;
int c = 42;
printf("entered\n");
while(count < 4){
*start = c;
start++;
count++;
}
}
and
char* find_blank(char *start){
char c;
int space = 127;
int null = 0;
while(*start){
c = *start;
int asciiVal = c;
if(asciiVal == 32 || asciiVal == 3){
return start;
}
start++;
}
}
the main method that im using to test it is:
int main(){
char myString3[25] = "Test a duck";
printf("The string before: %s\n", myString3);
censor(myString3);
printf("The new string: %s", myString3);
return 0;
}
And what I have is
void censor(char *start){
char* c = start;
while(*start){
int i = (int)find_blank(start) - (int)start;
start = start + i + 1;
c = start;
if((int)find_blank(start) - (int)c == 4){
four_stars(start);
}
start++;
}
}
#include <stdio.h>
void four_stars(char *start){
int count = 0;
int c = '*';
//printf("entered\n");
while(count < 4){
*start = c;
start++;
count++;
}
}
char* find_blank(char *start){
char c;
while(*start){
c = *start;
if(c == ' ' || c == '\t' || c == '\n'){
return start;
}
start++;
}
return start;
}
char* find_not_blank(char *start){
char c;
while(*start){
c = *start;
if(c != ' ' && c != '\t' && c != '\n'){
return start;
}
start++;
}
return NULL;
}
void censor(char *start){
while(start = find_not_blank(start)){
int len = find_blank(start) - start;
if(len == 4){
four_stars(start);
}
start += len;
}
}
int main(){
char myString3[25] = "Test a duck";
printf("The string before: %s\n", myString3);
censor(myString3);
printf("The new string: %s", myString3);
return 0;
}
There are a number of ways to do this. When learning C, one of the challenges is getting comfortable with the use of pointers for scanning strings. Along with that comes learning what C library functions are available to help with the scanning when needed. (you can always do it with pointers alone, but there are useful functions that can save you a lot of comparison work)
There are a couple of complicating factors to consider in scanning for 4-letter words. Most notable punctuation as word ends. One shortcut for handling multiple possible word ends is simply to create a string holding a collection of characters that can be at the end of a word instead of simple a space. Then the C library function strchr can be used to check if your ending character is in that collection.
Utilizing that, here is a short example of one approach to scanning a string for 4-letter words that may help you along:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void censor (char *s)
{
if (!s) return; /* validate s */
char *sp = s; /* start pointer */
char *ep = s; /* end pointer */
char *termchr = " ,.\n\t\0"; /* str of word ends */
while (*ep) /* for each char in string */
{
if (strchr (termchr, *ep)) /* if char in termchr */
{ /* and num chars == 4 */
if (ep - ((sp > s) ? ++sp : sp) == 4)
{
while (sp < ep) /* replace with '*' */
*sp++ = '*';
}
else
sp = ep; /* if not, just advance sp */
}
ep++;
}
}
int main (int argc, char **argv) {
if (argc < 2) {
fprintf (stderr, "\n error: insufficient input. Usage: %s <string>\n\n", argv[0]);
return 1;
}
char *str = strdup (argv[1]); /* make a copy to prevent clobbering argv[1] */
printf (" original string: %s\n", str);
censor (str);
printf (" censored string: %s\n", str);
return 0;
}
output:
$ ./bin/censor "A sting that has duck you dude."
original string: A sting that has duck you dude.
censored string: A sting **** has **** you ****.
Note: ((sp > s) ? ++sp : sp) is a simple test that says if I'm at the beginning, don't advance sp before comparing needed because your are at the beginning of a word already (the first word), not on the last termchr you found. You will probably want to come up with a scheme to exclude common words from replacement so you are not censoring words like this, that, with, most, good, word(s). That's left to you.