What does str[i - 1] == ' ' mean? - c

I've been reviewing a program that capitalises the first letter of every word in a string. For example, "every single day" becomes "Every Single Day".
I don't understand the part str[i - 1] == ' '. What does that do?
#include <stdio.h>
char *ft_strcapitalize(char *str)
{
int i;
i = 0;
while (str[i] != '\0')
{
if ((i == 0 || str[i - 1] == ' ') &&
(str[i] <= 'z' && str[i] >= 'a'))
{
str[i] -= 32;
}
else if (!(i == 0 || str[i - 1] == ' ') &&
(str[i] >= 'A' && str[i] <= 'Z'))
{
str[i] += 32;
}
i++;
}
return (str);
}
int main(void)
{
char str[] = "asdf qWeRtY ZXCV 100TIS";
printf("\n%s", ft_strcapitalize(str));
return (0);
}

i is the index in the string of the current character you are thinking about capitalising (remembering it starts at 0).
i-1 is the index in the string of the previous character to the one you are considering.
str[i-1] is the character in the position previous to the one you are considering.
== ' ' is comparing that character to a space character.
So str[i-1] == ' ' means "Is the character to the left of this one a space?"

It is checking for spaces, or more exactly, the line
if ((i == 0 || str[i - 1] == ' ')
Checks if we are looking at the string beginning or its previous line was a space, that is, to check if a new word was encountered.
In the string "every single day", i = 0 at the bold position, and in the next case,
"every single day", i = 6 and str[i-1] is ' ' marking a new word was encountered

"What does str[i - 1] == ' ' mean?"
' ' is a character constant for the white space character (ASCII value 32).
str is a pointer to char in the caller. (Practically thinking, it should point to an array of char with a string inside of it, not just a single char).
i is a counter.
Note that the C syntax allows that you can use array notation for pointers. Thus, str[1] is equal to *(str + 1).
The [i - 1] in str[i - 1] means that you access the element before the element str[i] is pointing to.
The element str[i - 1] is pointing to, is compared to the white space character (If the element str[i - 1] is pointing to actually contains white space).
The condition evaluates to true if this is the case, else the condition is false.
Side Notes:
Note that str[i - 1] can be dangerous when i == 0. Then you would try to access memory beyond the bounds of the pointed array. But in your case, this is secure since str[i - 1] == ' ' is only evaluated, if i == 0 is not true, thanks to the logical OR ||.
if ((i == 0 || str[i - 1] == ' ')
So this case is considered in your code.
str[i] -= 32; is equivalent to str[i] -= 'a' - 'A';. The latter form can improve readability as the capitalizing nature is brought to focus.

Here you are comparing str[i-1] with character space, Whose ASCII code is 32.
e.g.
if(str[i-1] == ' ')
{
printf("Hello, I'm space.\n");
}
else
{
printf("You got here, into the false block.\n");
}
Execute this snippet and if the comparison yields the value 1 it's true, false otherwise. Put str[] = "Ryan Mney"; and then compare you'll understand, what is happening?

The C-language provides a number of useful character macros that can be used to both make code more portable, and more readable. Although the sample code you are reviewing does not use these macros, please consider using these macros to make your code more portable, more robust, and easier for others to read.
Please use the islower/isupper/isalpha and tolower/toupper macros; these ctype macros make C-language string processing easier to read.
islower(ch) - check whether ch is lower case
isupper(ch) - check whether ch is upper case
isalpha(ch) - check whether ch is alphabetic (lower or upper case)
tolower(ch) - convert ch to lower case (if it is alphabetic)
toupper(ch) - convert ch to upper case (if it is alphabetic)
Yes, they are macros -
What is the macro definition of isupper in C?
The C-language provides the 'for' control statement which provides a nice way to express string processing. Simple indexed loops are often written using 'for' rather than 'while'.
#include <ctype.h>
char*
ft_strcapitalize(char *str)
{
for( int i=0; (str[i] != '\0'); i++ )
{
if ((i == 0 || isspace(str[i - 1])) && islower(str[i]) )
{
str[i] = toupper(str[i]);
}
else if (!(i == 0 || str[i - 1] == ' ') && isupper(str[i]) )
{
str[i] = tolower(str[i]);
}
}
return (str);
}
A slight refactoring makes the code a bit more readable,
char*
ft_strcapitalize(char *str)
{
for( int i=0; (str[i] != '\0'); i++ )
{
if( (i == 0 || isspace(str[i - 1])) )
{
if( islower(str[i]) ) str[i] = toupper(str[i]);
}
else if( !(i == 0 || isspace(str[i - 1]) )
{
if( isupper(str[i]) ) str[i] = tolower(str[i]);
}
}
return(str);
}
Alternately, use isalpha(ch),
char*
ft_strcapitalize(char *str)
{
for( int i=0; (str[i] != '\0'); i++ )
{
if( (i == 0 || isspace(str[i - 1])) )
{
if( isalpha(str[i]) ) str[i] = toupper(str[i]);
}
else if( !(i == 0 || isspace(str[i - 1]) )
{
if( isalpha(str[i]) ) str[i] = tolower(str[i]);
}
}
return(str);
}
Simplify the conditional expression even further, by performing the special case (first character of string) first.
char*
ft_strcapitalize(char *str)
{
if( islower(str[0]) ) str[0] = toupper(str[0]);
for( int i=1; (str[i] != '\0'); i++ )
{
if( isspace(str[i - 1]) )
{
if( islower(str[i]) ) str[i] = toupper(str[i]);
}
else if( !isspace(str[i - 1]) )
{
if( isupper(str[i]) ) str[i] = tolower(str[i]);
}
}
return(str);
}
Again, the alternate isalpha(ch) version,
char*
ft_strcapitalize(char *str)
{
if( isalpha(str[0]) ) str[0] = toupper(str[0]);
for( int i=1; (str[i] != '\0'); i++ )
{
if( isspace(str[i - 1]) )
{
if( isalpha(str[i]) ) str[i] = toupper(str[i]);
}
else if( !isspace(str[i - 1]) )
{
if( isalpha(str[i]) ) str[i] = tolower(str[i]);
}
}
return(str);
}
Even more idiomatic, just use a 'state' flag that indicates whether we should fold to upper or lower case.
char*
ft_strcapitalize(char *str)
{
int first=1;
for( char* p=str; *p; p++ ) {
if( isspace(*p) ) {
first = 1;
}
else if( !isspace(*p) ) {
if( first ) {
if( isalpha(str[i]) ) str[i] = toupper(str[i]);
first = 0;
}
else {
if( isalpha(str[i]) ) str[i] = tolower(str[i]);
}
}
}
return(str);
}
And your main test driver,
int main(void)
{
char str[] = "asdf qWeRtY ZXCV 100TIS";
printf("\n%s", ft_strcapitalize(str));
return (0);
}

' ' is a character constant representing the value of the space character in the execution set. Using ' ' instead of 32 increases both readability and portability to systems where space might not have the same value as in the ASCII character set. (i == 0 || str[i - 1] == ' ') is true if i is the offset of the beginning of a word in a space separated list of words.
It is important to try and make the as simple and readable as possible. Using magic constants like 32 is not recommended when a more expressive alternative is easy and cheap. For example you convert lowercase characters to uppercase with str[i] -= 32: this magic value 32 (again!) happens to be the offset between the lowercase and the uppercase characters. It would be more readable to write:
str[i] -= 'a' - 'A';
Similarly, you wrote the range tests for lower case and upper case in the opposite order: this is error prone and surprising for the reader.
You are also repeating the test for the start of word: testing for lower case only at the start of word and testing for upper case otherwise makes the code simpler.
Finally, using a for loop is more concise and less error prone than the while loop in your function, but I known that the local coding conventions at your school disallow for loops (!).
Here is a modified version:
#include <stdio.h>
char *ft_strcapitalize(char *str) {
size_t i;
i = 0;
while (str[i] != '\0') {
if (i == 0 || str[i - 1] == ' ') {
if (str[i] >= 'a' && str[i] <= 'z') {
str[i] -= 'a' - 'A';
}
} else {
if (str[i] >= 'A' && str[i] <= 'Z') {
str[i] += 'a' - 'A';
}
}
i++;
}
return str;
}
int main(void) {
char str[] = "asdf qWeRtY ZXCV 100TIS";
printf("\n%s", ft_strcapitalize(str));
return 0;
}
Note that the above code still assumes that the letters form two contiguous blocks in the same order from a to z. This assumption holds for the ASCII character set, which is almost universal today, but only partially so for the EBCDIC set still in use in some mainframe systems, where there is a constant offset between cases but the letters from a to z do not form a contiguous block.
A more generic approach would use functions and macros from <ctype.h> to test for whitespace (space and other whitespace characters), character case and to convert case:
#include <ctype.h>
char *ft_strcapitalize(char *str) {
for (size_t i = 0; str[i] != '\0'; i++) {
if (i == 0 || isspace((unsigned char)str[i - 1]))
str[i] = toupper((unsigned char)str[i]);
else
str[i] = tolower((unsigned char)str[i]);
}
return str;
}

Related

Can someone explain me why I am not able to check special characters in my string using ASCII values?

So, my code actually works perfectly when I use function that checks for special characters in string by explicitly giving symbols:
int isSpecialCharacter(char str[], int n)
{
for(int i=0; i<n;i++)
{
if (str[i] == '!' || str[i] == '#' || str[i] == '#' || str[i] == '$' || str[i] == '%' || str[i] == '^' || str[i] == '(' || str[i] == ')')
{
return 1;
}
return 0;
}
}
However, in the below code I am not able to get my code to find special characters in string using ASCII values. I want to understand what am I doing wrong. In the below code, I have my main() also included that prompts the user to input string.
#include <stdio.h>
#include <string.h>
char str[30][30];
char test[100];
int myindex = 0;
int isSpecialCharacter(char str[], int n)
{
for(int i=0; i<n;i++)
{
if (str[i] == 33 || str[i] == 35 || str[i] == 36 || str[i] == 37 || str[i] == 40 || str[i] == 41 || str[i] == 64)
{
return 1;
}
return 0;
}
}
int main()
{
printf("Please enter 10 strings below: \n");
while(myindex < 10)
{
printf("Enter string %d: ", myindex+1);
fgets(str[myindex], 500, stdin);
strcpy(test, str[myindex]);
int t_size = strlen(test);
if (strlen(str[myindex])<2||strlen(str[myindex])>26)
{
printf("Enter string that is between 2 and 25");
continue;
}
else if(isSpecialCharacter(test, t_size) == 1)
{
printf("Your string has some special characters. \n");
continue;
}
else
{
myindex++;
}
}
return 0;
}
EDIT:
I have included the variable declarations and replaced the code where I use symbols to check for special characters. Thank you.
EDIT2:
These are the characters that I want to look for: : ’!’, ’#’, ’#’, ’$’, ‘%’, ‘^’, ’(’, or ’)’. Not spaces.
Both your functions won't work as you've written them.
The main problem is that the for loop returns after each loop cycle, so you never check beyond the first cycle.
You should move the return 0 statement to the end of the function, then it will work as expected.
int isSpecialCharacter(char str[], int n)
{
for (int i = 0; i < n; i++)
{
if (str[i] == 33 || str[i] == 35 || str[i] == 36 || str[i] == 37 || str[i] == 40 || str[i] == 41 || str[i] == 64)
{
return 1;
}
}
return 0;
}
Test
I've tested the solution with the following input:
test1
test2
test)
test(
test3
test4
test5
test#
test6
test7
test!
test8
test9
test10
And it works. You can see the result there: https://godbolt.org/z/67Px14z75
As suggested from other users in the comment section, using decimal values to refer to characters is a bad practice™ and you should stick with the '#' notation.
Your return 0; is incorrect:
int isSpecialCharacter(char str[], int n) {
for(int i=0; i<n;i++)
{
if (str[i] == '!' || str[i] == '#' || str[i] == '#' || str[i] == '$' || str[i] == '%' || str[i] == '^' || str[i] == '(' || str[i] == ')')
{
return 1;
}
return 0;
}
}
On the very first loop, your function returns either 1 or 0. You only want to return 0 (false) if the loop completes without finding the character you're looking for.
int isSpecialCharacter(char str[], int n)
{
for(int i=0; i<n;i++)
{
if (str[i] == '!' || str[i] == '#' || str[i] == '#' || str[i] == '$' || str[i] == '%' || str[i] == '^' || str[i] == '(' || str[i] == ')')
{
return 1;
}
}
return 0;
}
I'm not going to try to write your code...
if( isSpecialCharacter()
is equivalent to:
if( strpbrk( test, "abqmz" ) != NULL )
(except that the latter has been proven to work...)
If a, b, q, m, z appear in the string, then the if condition is true...
Learn the standard library instead of spending time badly reinventing it...
EDIT:
Here is how an experienced programmer might write that functionality now that you've decoded the decimal ASCII values. (Don't expect the next programmer who reads your code to reach for their ASCII table...)
char spcl[] = "!##$%^()";
if( strpbrk( test, spcl ) != NULL ) {
// Do something because condition is true
NB: if you need to make either \ or " special inside a string, you must 'escape' either of those characters with an 'extra' backslash. Eg:
char spcl[] = "\\!##$%^(\")"; // notice '\\' and '\""
If that looks too much like "bad language", you can construct your own string (ENSURING(!) that it is null terminated.)
char spcl[] = { '\\', '!', '#', '#', '$', '%', '^', '(', '\"', ')' '\0' };
And...
char str[30][30];
/* Skipping ahead */
printf("Enter string %d: ", myindex+1);
fgets(str[myindex], 500, stdin); // 500!!! ????
is simply looking for trouble...
The position of "return 0" is not correct.
It should come after the end of "for loop"

Find spaces and alphanumeric characters in a string C Language

Hi i'm trying to build a function in C language that checks if the string contains numbers , upper cases and lower cases and space, if the string contains any other character then those the function return -1.
float avg_word_len(char* str)
{
float check;
for (int i = 0; i < strlen(str); i++)
{
if (((str[i] >= '0') && (str[i] <= '9')&&(str[i] >= 'a') && (str[i] <= 'z') && (str[i] == ' ')&& (str[i] >= 'A') && (str[i] <= 'Z')))
check = 1;
else
check = -1;
}
str = '\0';
return check;
that's my code ,but the function keep return -1 please help
Some of your && must replaced by || because one character is a number OR a lower case OR a space OR an upper case, but it cannot be all these things at a time :
check = 1;
for (int i = 0; i < strlen(str); i++)
{
if (! (((str[i] >= '0') && (str[i] <= '9')) ||
((str[i] >= 'a') && (str[i] <= 'z')) ||
(str[i] == ' ') ||
((str[i] >= 'A') && (str[i] <= 'Z')))) {
check = -1;
break;
}
}
You can use these three function which are countain in the hreader #include <ctype.h>
isalpha : Checks if a character is alphabetic (upper or lower case).
isdigit : Checks if a character is a number.
isblank : Checks whether a character is blank or not.
#include <ctype.h>
#include <stdio.h>
float avg_word_len(char* string)
{int check=-1;
for(int i=0;string[i]!='\0';i++)
{
if(isalpha(string[i])||isdigit(string[i])||isblank(string[i]))
{
check=1;
}
}
return check;
}
int main()
{
char string[150];
printf("Give me a text :");
scanf("%s[^\n]",string);
printf("\n%.f\n",avg_word_len(string));
}
As Weather Vane commented, a lot of those &&s should be ||s - additionally, parentheses should surround each range (e.g. ('0' <= str[i] && str[i] <= '9'))).
To check whether the character is in a range, we use AND (i.e. the character is above the lower bound AND below the upper bound). To check whether the character is in one of multiple ranges, we use OR (i.e. the character is in range 1 OR it is in range 2 OR...).
If we were to only fix that, here's how the if condition would look:
(str[i] >= '0' && str[i] <= '9') || (str[i] >= 'a' && str[i] <= 'z') || (str[i] == ' ') || (str[i] >= 'A' && str[i] <= 'Z')
Having said that, I would suggest using the function isalnum from ctype.h in the standard library, which checks if a character is alphanumeric. It makes the code much simpler and avoids the assumption that characters are ordered in such a way that all lowercase letters lie between 'a' and 'z' (which is true in ASCII - which is what is used in practice - but is not standard).
In addition, I would suggest initializing check to -1 and breaking early from the loop once you find a non-alphanumeric, non-space character so that a -1 is not later overwritten by a 1 (as would happen in the current version of your code).
This is what it would look like:
float check = -1;
for (int i = 0; i < strlen(str); i++)
{
if (!isalnum(str[i]) && str[i] != ' ') {
check = 1;
break;
}
}

Program to find vowels, If statements not assigning correct values [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I have a simple program to find the vowels in a string. The for loop is supposed to iterate through the string and see if the char matches any of the vowels using and if else block but the output is just 100 As.
I tried making them all just ifs but that gave all Us.
#include <stdio.h>
int main()
{
const int SIZE = 100;
char str[SIZE] = {"the brown fox\0"};
char vowels[SIZE];
for (int i = 0; i <= SIZE; i++) {
if (str[i] == '97' || '65') {
vowels[i] = 'a';
}
else if (str[i] == '101' || '69' ) {
vowels[i] = 'e';
}
else if (str[i] == '105' || '73') {
vowels[i] = 'i';
}
else if (str[i] == '111' || '81') {
vowels[i] = 'o';
}
else if (str[i] == '117' || '85') {
vowels[i] = 'u';
}
printf("%c", vowels[i]);
}
return 0;
}
EDIT: Fixed the assignment if e.g. (str[i] == '97' || str[i] == '65') now it's printing strange symbols
EDIT 2: New code
#include <stdio.h>
int main()
{
const int SIZE = 100;
char str[SIZE] = {"the brown fox\0"};
char vowels[SIZE];
for (int i = 0; i <= SIZE; i++) {
if (str[i] == 'a' || str[i] == 'A') {
vowels[i] = 'a';
}
else if (str[i] == 'e' || str[i] =='E' ) {
vowels[i] = 'e';
}
else if (str[i] == 'i' || str[i] == 'I') {
vowels[i] = 'i';
}
else if (str[i] == 'O' || str[i] == 'o') {
vowels[i] = 'o';
}
else if (str[i] == 'u' || str[i] == 'U') {
vowels[i] = 'u';
}
printf("%c", vowels[i]);
}
return 0;
}
EDIT 3: Even after initialing vowels to '' at the start of the loop as suggested the strange symbols are gone but it's still not functioning properly.
You are comparing your char str[i] with '97'
6.4.4.4
An integer character constant has type int. The value of an integer character constant containing a single character that maps to a single-byte execution character is the numerical value of the representation of the mapped character interpreted as an integer. The value of an integer character constant containing more than one character (e.g., 'ab'), or containing a character or escape sequence that does not map to a single-byte execution character, is implementation-defined.
If you want to compare a char you can use the ascii value for example 97 or directly the char with 'c'.
For more maintenability and readability I prefer using the char directly.
There is other problems in your code:
First, in your for loop: for (int i = 0; i <= SIZE; i++) {
You are going too far in your array because of your <= as arrays id starts with 0, if you type str[100], in reality you are using the 101st char.
Another problem is your if statements: if (str[i] == '97' || '65') {
Here your if statement is equivalent to if (str[i] == '97' || '65' != 0) {
Consider retyping str[i] == : if (str[i] == '97' || str[i] == '65') {
Plus don't forget the first problem I mentionned about your '97'
You have a very large number of small problems summarized below:
#define SIZE 100 /* if you need a constant, #define one (or more) */
...
char vowels[SIZE] = ""; /* initialize all zero, {0) is valid also */
An integer constant is created by #define or by use of an enum. A const qualified int is not a constant integer. (that said VLAs are legal in C99, but optional in C11)
int idx = 0; /* separate index for filling vowels array */
Keep a separate index for filling the vowels array.
/* don't use magic-numbers in your code */
if (str[i] == 'a' || str[i] == 'A') {
Don't use magic-numbers, instead, use literal character constants were needed in your code to produce much more readable code.
Your program takes arguments, use them to pass the string to parse (or read from stdin), e.g.
int main (int argc, char **argv) {
const char *str = (argc > 1) ? argv[1] : "the brown fox";
...
The test ? if_true : if_false operator is called the ternary operator. It allows a simple in-line conditional to select one of two values based on the test condition (e.g. (argc > 1))
If you plan on using vowels as a string, don't forget to nul-terminate vowels after the loop, e.g.
vowels[idx] = 0; /* nul-terminate vowels */
Correcting all the errors and adding the arguments to main() you could do something similar to:
#include <stdio.h>
#define SIZE 100 /* if you need a constant, #define one (or more) */
int main (int argc, char **argv) {
const char *str = (argc > 1) ? argv[1] : "the brown fox";
char vowels[SIZE] = ""; /* initialize all zero, {0) is valid also */
size_t idx = 0; /* separate index for filling vowels array */
for (int i = 0; idx < SIZE - 1 && str[i]; i++) {
/* don't use magic-numbers in your code */
if (str[i] == 'a' || str[i] == 'A') {
vowels[idx++] = 'a'; /* assign 'a', increment index */
}
else if (str[i] == 'e' || str[i] == 'E' ) {
vowels[idx++] = 'e';
}
else if (str[i] == 'i' || str[i] == 'I') {
vowels[idx++] = 'i';
}
else if (str[i] == 'o' || str[i] == 'O') {
vowels[idx++] = 'o';
}
else if (str[i] == 'u' || str[i] == 'U') {
vowels[idx++] = 'u';
}
}
vowels[idx] = 0; /* nul-terminate vowels */
printf (" %zu vowels: ", idx); /* print number of vowels */
for (int i = 0; vowels[i]; i++) /* output each vowel, comma-separated */
printf (i > 0 ? ", %c" : "%c", vowels[i]);
putchar ('\n'); /* tidy up with newline */
return 0;
}
Example Use/Output
bin\vowels.exe "a quick brown fox jumps over the lazy dog"
11 vowels: a, u, i, o, o, u, o, e, e, a, o
Depending on your compiler str[i] == '117' (and the rest) may give you an error as signle quotes are only to be used when you want to implement the ascii equivalent of a single character like 'a' or so. Therefore str[i] == '117' is checking if str[i] is equal to the ascii equivalent of "117".
Other than that " || " is a logical "or" operator. When you write down str[i] == '111' || '81' you simply mean "find ascii codes of 111 and 81(which dont exist) , use them in "or" operation, check if the result equals str[i]".
last but not least i found a nice function online which might help making your code more compact
int isvowel(int ch)
{
int c = toupper(ch);
return (c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U');
}
to explain it shortly, if the char equivalent of given int ch is lowercase, the function changes it to uppercase and checks if it is an uppercase vowel, if the given integer already equals an uppercase vowel int c = toupper(ch); doesnt change anything.
Implementation can be done as:
for(int i=0; i<SIZE; i++) //scan all emelents of str[SIZE]
{
if(isvowel(str[i])) //print if vowel
printf ("%c", str[i]);
}

Char as a decimal separator in C

I've written a function that extracts double from a string. Like asfas123123afaf to 123123 or afafas12312.23131asfa to 12312.23131 using the point as a decimal separator.
Here is the code:
double get_double(const char *str, char sep)
{
char str_dbl[80];
size_t i,j;
char minus;
double dbl;
for (minus = 1, i = j = 0; i < strlen(str); ++i)
{
if (
(str[i] == '-' && minus)
|| (str[i] >= '0' && str[i] <= '9')
|| (str[i] == 'e' || str[i] == 'E')
)
{
str_dbl[j++] = str[i];
minus = 0;
}
}
str_dbl[j] = '\0';
dbl = strtod (str_dbl,NULL);
return dbl;
}
But now I want to set a user defined comma separator (char sep) from the ASCII-chars (without E or e that are literals for ^10). How could I implement it?
Let me sepcify this: We say the separator is ',' so the string is 123123asfsaf,adsd,as.1231 it should return 123123,1231 as a double. It recognizes the first ',' (from left) and ignore all other.
It is really hard for me to find a solution for this problem. I have thought about setlocale but I it doesn't seem the best solution.
Thank you!
You can just replace any , with . before doing the strtod.
If you for some reason don't want to modify the source string, copy it to a new string first.
Well I know that using String.Split does this sor of thing but I think you should write your own function for it stop when it found the first one.
here is the msdn website for more help on that
MSDN Split
You can simply extend your code:
if (
(str[i] == '-' && minus)
|| (str[i] >= '0' && str[i] <= '9')
|| (str[i] == 'e' || str[i] == 'E')
)
to
char separator = ','; //or whatever you want
int have_separator = 0;
if (
(str[i] == '-' && minus)
|| (str[i] >= '0' && str[i] <= '9')
|| (str[i] == 'e' || str[i] == 'E')
|| str[i] == separator
)
{
if (str[i] == separator && have_separator == 0)
{
have_separator = 1;
str_dbl[j++] = str[i];
continue;
}
...
Please note that this is only some try to show the idea - not the real working code (but it could work anyway). You can use similar concept.

How to replace specific characters in a string with other characters

I am trying to make a program that will take as input a string and replace all the vowels with the * symbol. So, for "hello world", star_vowels should return "h*ll* w*rld".
What I have for code so far is:
int star_vowels(char s[]){
int j;
j = 0;
while (s[j] != '0'){
j++;
if (s[j] = 'a' || s[j] == 'e' || s[j] == 'i' || s[j] == 'o' || s[j] == 'u'){
putchar('*');
} else {
putchar(j);
}
return 0;
}
}
This code has a number of things wrong with it.
1) while (s[j] != '0')
I'm fairly sure you want to be checking for the NUL character, not the character constant zero. Change '0' to '\0'
2) j++
you are incrementing j before you even look at the 0th index of your array. If you had a vowel at s[0], this would be missed. Move j++ to the very bottom of the while loop, just before the ending brace.
3) s[j] = 'a'
You are using the assignment operator = here when you should be using the equality operator == instead. Using the assignment operator is legal C code and thus will compile. Unfortunately it will return true and you'll end up replacing all of your characters with asterisks
4) putchar(j);
You are attempting to output 'j' (your iterator) when you really want to be outputting s[j] (your character).
5) return 0
just like in #2, your return statement is in the wrong place. You have it within the while loop when it should be outside of it. The way you have it written, the while loop will only execute the first iteration before your function goes out of scope.
int star_vowels(char s[]) {
int j = 0;
while (s[j] != '\0'){
if (s[j] == 'a' || s[j] == 'e' || s[j] == 'i' || s[j] == 'o' || s[j] == 'u') {
putchar('*');
} else {
putchar(s[j]);
}
j++;
}
return 0;
}
I think your question is going to be 'everything is *' and that's because of this part of your giant if:
if (s[j] = 'a'
That will always be true. You need the ==
Also you put j++ too early - you'd skip characters because you immediately increment upon entering the loop.
By incrementing the j at the beginning you will lose the 0 index (the first character).
Since you want to return new data to the outside world (outside the function scope), you either allocate memory for the new data outside the function, and pass in a pointer of that data to this function, or you just allocate dynamic memory inside this function - remember to delete it.
One implementation would be:
char *star_vowels(char s[]){
// let's allocate memory for the new string.
// its size should be strlen(s) + 1 (the ending char).
char *final = malloc(strlen(s) + 1);
int j = 0;
while (s[j] != 0){
if (s[j] == 'a' || s[j] == 'e' || s[j] == 'i' || s[j] == 'o' || s[j] == 'u'){
final[j] = '*';
} else {
final[j] = s[j];
}
j++;
}
final[j] = 0; // end the string
return final;
}
Working example: http://codepad.org/dd2w5cuy

Resources