I created a program. It works as I wanted it to work, but I don't understand why.
This is the function.
void LiteraMajuscula(char *str)
{
int i;
i = 0;
while (str[i] != '\0')
{
if (i == 0 && str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
if (str[i-1] == ' ' && str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
i++;
}
}
It is supposed to make the lowercase character into an uppercase one each time there is a space and only the first one and if the first character from a string is lowercase, make it an uppercase.
The only thing i dont understand is the str[i-1]. I tried str[i], but it doesn't change anything, and str[i-2] changes the second letter into and uppercase instead of the first one. Why is that?
str[i] -= 32; will convert the character at index i. The reason the second if statement uses str[i-1] == ' ' in its check is so it knows whether the current character (at i) is just after a space (at i - 1). The reason it converted the second character of words when you changed it to str[i-2] == ' ' is that you changed it so it converted a character if it (at i) was two characters after a space (at i-2).
As noted in the comments, the code there has undefined behavior, because there's nothing preventing the str[i-1] == ' ' check when i is 0, so str[i-1] would be accessing the character before where str is pointing.
Separately, since most of the conditions and logic are duplicated between the two ifs, this is where you'd use || (logical OR):
while (str[i] != '\0')
{
if ((i == 0 || str[i-1] == ' ') && str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
i++;
}
(Note the () around the ||.)
|| short-circuits, so when i is 0 and the first operand is true, the second operand (str[i-1] == ' ') is never evaluated and so you avoid undefined behavior.
The body of the loop is incorrect
while (str[i] != '\0')
{
if (i == 0 && str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
if (str[i-1] == ' ' && str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
i++;
}
When i is equal tp 0 then in this condition
if (str[i-1] == ' ' && str[i] >= 'a' && str[i] <= 'z')
^^^^^^^^
there is an attempt to access memory beyond the string. The loop should be rewritten at least like
while (str[i] != '\0')
{
if ( ( i == 0 || str[i-1] == ' ' ) && str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
i++;
}
That is the condition checks whether the first character of the string is an alpha character or if it is not the first character of the string whether the previous character is space and the current character is an alpha character.
Take into account that the function will not work with EBCDIC characters. It is better to use standard C function toupper declared in header <string.h>. For example
while (str[i] != '\0')
{
if ( i == 0 || str[i-1] == ' ' )
{
if (isalpha((unsigned char)s[i]) ) s[i] = toupper((unsigned char)s[i]);
}
i++;
}
I think it is desirable also to check whether the previous character is the tab character. Also such string functions usually return the target string.
I would write the function the following way
#include <stdio.h>
#include <ctype.h>
char * LiteraMajuscula( char *s )
{
for (size_t i = 0;
s[i += strspn(s + i, " \t")] != '\0';
i += strcspn( s + i, " \t" ))
{
if (isalpha((unsigned char)s[i]) ) s[i] = toupper((unsigned char)s[i]);
}
return s;
}
int main(void)
{
char s[] = "hello,\tworld!";
puts(s);
puts(LiteraMajuscula(s));
return 0;
}
Its output is
hello, world!
Hello, World!
The other answers posted have explained what was wrong with the code.
Here is an alternative way that the function can be rewritten to be more efficient and more portable, with the use of functions from ctype.h:
void do_some_incorrect_capitalization (char str[])
{
if(*str == '\0')
{
return ;
}
*str = toupper(*str); // special case, first letter in the string
str++;
while(*str != '\0')
{
if(isspace(*(str-1)))
{
*str = toupper(*str);
}
str++;
}
}
Related
I am trying to capitalize every word in and here is my code:
char *cap_string(char *str)
{
int i;
for (i = 0; str[i] != '\0'; i++)
{
if (i == 0)
{
if (str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
continue;
}
if (str[i] == ' ')
{
++i;
if (str[i] >= 'a' && str[i] <= 'z')
{
str[i] -= 32;
continue;
}
}
else
{
if (str[i] == '.')
{
++i;
if (str[i] >= 'a' && str[i] <= 'z')
{
str[i] -= 32;
continue;
}
}
}
}
return (str);
}
My question is that my code works fine in most cases, but does not function properly if it encounters multiple white spaces. How can I capitalize a word preceded by multiple white spaces?
Change your code to the following:-
char *cap_string(char *str)
{
int i;
for (i = 0; str[i] != '\0'; i++)
{
if (i == 0 || str[i - 1] == ' ' || str[i - 1] == '.' || str[i-1] == '\n')
{
if (str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
}
}
return (str);
}
Testing all cases, using the following code,
#include <stdio.h>
int main()
{
char str[] = "hello world.hello";
printf("%s", cap_string(str));
return 0;
}
returns
Hello World.Hello
I have tried to keep your logic intact and not use any string.h library functions.
You have to keep in mind that the other conditions after the || operator are not checked if the first condition is evaluated as true. So str[-1] never occurs.
The main idea is look at the previous letter to see if the current letter has to upper case. Introduced a constant UPCASE_AFTER so it's easy to add other punctuation marks (say, '!', '?'). Added test case. Refactored for readability.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#define UPCASE_AFTER " ."
char *cap_string(char *str) {
for (int i = 0; str[i]; i++) {
if (!i || strchr(UPCASE_AFTER, str[i-1])) {
str[i] = toupper(str[i]);
}
}
return str;
}
int main() {
printf("%s\n", cap_string((char []) {"a bb c.d.ee..f."}));
return 0;
}
and it returns:
A Bb C.D.Ee..F.
Here's another alternative:
#include <stdio.h>
// Use standard library routines
// like 'isalpha()', 'toupper'...
// Not all character sets have ASCII's contiguous alphabets.
#include <ctype.h>
char *cap_string( char *str ) {
bool flag = true; // 'state flag' indicating "hunting for lowercase letter"
for( char *cp = str; *cp; cp++ )
if( flag && islower( *cp ) ) {
*cp = (char)toupper( *cp );
flag = false;
}
else
flag = !isalpha( *cp );
return str; // 'return' is not a function call
}
int my_main() {
char str[] = "what? now is the time (we say sometimes) to learn C.";
printf( "%s\n", cap_string( str ) );
return 0; // 'return' is not a function call
}
Output
What? Now Is The Time (We Say Sometimes) To Learn C.
I have an assignment like
the codes must capitilize the first letter after period and put a space.
I wrote a function like that which capitalize the first letter after period.
for (i = 0; str[i] != '\0'; i++)
{
if (i == 0)
{
if ((str[i] >= 'a' && str[i] <= 'z'))
str[i] = str[i] - 32;
continue;
}
if (str[i] == '.' || str[i] == '!' || str[i] == '?')
{
++i;
if (str[i] >= 'a' && str[i] <= 'z')
{
str[i] = str[i] - 32;
continue;
}
}
else
{
if (str[i] >= 'A' && str[i] <= 'Z')
str[i] = str[i] + 32;
}
}
But I couldn't do the putting space part can someone help me pls
Adding spaces in your string means you're final string will contain more characters than the original one.
Thus you'll need to allocate memory, using malloc.
What you can do is:
Get the period count in your string
Deduce the number of spaces you'll have to add
Allocate a new string that is strlen(old_string) + space_count + 1 long
Finally iterate through your old string, copying / modifying each character you want to, and adding a space in the new string when needed
Let me know if it's not clear enough, or if you need more precise informations.
Do not use magic numbers. Use standard functions instead.
passed string has to be modifiable and has enough room to accommodate new spaces.
The function below adds space after characters listed in the after string. If there is a blank space after this character it does not and skips all the blank spaces, then capitalize the first non-blank character. It does not add space if the character listed in after is the last in the string.
char *addSpaceAndCapitalizeAfter(char *str, const char *after)
{
char *wrk = str;
if(str && after)
{
while(*str)
{
if(strchr(after, *str))
{
if(str[1] && !isblank((unsigned char)str[1]) && str[2])
{
memmove(str + 2, str + 1, strlen(str) + 1);
str[1] = ' ';
str++;
}
str++;
while(*str && isblank((unsigned char)*str)) str++;
if(*str) *str = toupper((unsigned char)*str);
}
else
{
str++;
}
}
}
return wrk;
}
int main(void)
{
char str[100] = ",test,string, some, words,";
printf("`%s`\n", addSpaceAndCapitalizeAfter(str, ","));
}
https://godbolt.org/z/ecq1zxqYW
I am getting an int of the entire string s for 'letter', the conditions in my 'if' statement seem to not be reading properly - is my syntax incorrect?
I get user input:
string s = get_string("Text here: ");
the function is as follows:
int letter_count(string s)
{
int i =0;
int len = strlen(s);
int letter = 0;
while(i < len)
{
if (s[i] != '\0' || s[i] != '.' || s[i] != ',' || s[i] != '!' || s[i] != '?')
{
letter++;
}
i++;
}
return letter;
}
then call the function:
int letter = letter_count(s);
printf("letter Count: %i\n", letter);
Try changing the OR operator with the AND
if (s[i] != '\0' || s[i] != '.' || s[i] != ',' || s[i] != '!' || s[i] != '?')
is ALWAYS true. Because any character is either not "." or not ",". Which letter would you expect to be both?
You want to check whether the current letter is "not ." AND "not ," AND "not !".
I.e.
if (s[i] != '\0' && s[i] != '.' && s[i] != ',' && s[i] != '!' && s[i] != '?')
Almost correct, you have to change the type of the argument to char*, there is no string type on the default libraries. (Documentation of string library).
Working example with the modifications:
#include <stdio.h>
#include <string.h>
int letter_count (char* s)
{
int i = 0;
int len = strlen (s);
int letter = 0;
while (i < len)
{
if (s[i] != '\0' && s[i] != '.' && s[i] != ',' && s[i] != '!'
&& s[i] != '?')
{
letter++;
}
i++;
}
return letter;
}
int main ()
{
char my_word[] = "Sample word";
printf ("'%s' have %d letters",my_word, letter_count (my_word));
return 0;
}
Output:
'Sample word' have 11 letters
I have this exercise who capitalize the first character in given sentence.Please i can't understood what "i - 1" and str[i - 1] means
#include <stdio.h>
char* ft_strcapitalize(char *str)
{
int i;
i = 0;
while (str[i])
{
if ((i - 1 == 0 && str[i] != ' ')
|| (str[i - 1] >= 'a' && str[i - 1] <= 'z')
|| (str[i - 1] >= 'A' && str[i - 1] <= 'Z')
|| (str[i - 1] >= '1' && str[i - 1] <= '9'))
{
}
else if (str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
i++;
}
return (str);
}
int main(void)
{
char s[] = "salut, comment tu vas ? 42mots quarante-deux; cinquante+et+un";
ft_strcapitalize(s);
printf("%s", s);
}
Please i can't understood what "i - 1" and str[i - 1] means
str[i - 1] attempts to access the previous character in the string - the one before str[i]. It is bad code to use when i==0.
Create a function that capitalizes the first letter of each word and transforms all other letters to lowercase
Keep a state variable that identifies the next character may start a sentence. Use character handling functions from <ctype.h>.
#include <ctype.h>
#include <stdbool.h>
char* ft_strcapitalize(char *str) {
size_t i = 0;
bool start = true;
while (str[i]) {
if (start && isalpha(str[i])) {
str[i] = toupper(str[i]);
start = false;
} else {
str[i] = tolower(str[i]);
// TBD: Adjust 'start' detection as needed.
if (str[i] == '.' || str[i] == '?' || str[i] == '!') {
start = true;
}
}
i++;
}
return str;
}
I am constructing a program that takes string input from the keyboard then shows the number of consonants as an output. I have managed to do it in a ridiculous way in the function count_consonants. I tested using if statement whether each character in the input is a number or symbol to ignore them during calculations. I originally wanted to check if the string is not a string using fgets but I don't know how. That's not an effective way, so any ideas for this?
#include <stdio.h>
#include <string.h>
//function to calculate the consonants
int count_consonants(char str[]) {
int idx;
for (idx = 0; idx < 100; ++idx) {
if (str[idx] == '\0') {
break;
}
}
int vowl = 0;
for (int i = 0; i < idx; ++i) { //loop to check if the characters are vowels or not
if (str[i] == 'a' || str[i] == 'e' || str[i] == 'i' || str[i] == 'o'
|| str[i] == 'u' || str[i] == 'A' || str[i] == 'E' || str[i] == 'I'
|| str[i] == 'O' || str[i] == 'U' || str[i] == ' ') {
vowl += 1;
}
// numbers and symbols are counted here as vowels because if not,
// the compiler will count them the other way around
if (str[i] == '1' || str[i] == '2' || str[i] == '3' || str[i] == '4'
|| str[i] == '5' || str[i] == '6' || str[i] == '7' || str[i] == '8'
|| str[i] == '9') {
vowl += 1;
}
if (str[i] == ':' || str[i] == ',' || str[i] == '.' || str[i] == '$'
|| str[i] == '%' || str[i] == '^' || str[i] == '&' || str[i] == '*'
|| str[i] == '#' || str[i] == '_' || str[i] == '!') {
vowl += 1;
}
}
int cons = idx - vowl; // consonants = whole length of text - vowels
return cons - 1;
}
int main(int argc, char const *argv[]) {
char string[100];
char store[100][100];
int i = 0;
while (string[0] != '\n') {
fgets(string, 100, stdin);
strcpy(store[i], string);
i++;
}
for (int j = 0; j < i - 1; ++j) {
/* code */
printf("Number of consonants=%d\n", count_consonants(store[j]));
}
return 0;
}
shows the number of consonants
A simply way to count consonants, use isalpha(), strchr()
#include <string.h>
#include <ctype.h>
int my_isavowel(char ch) {
const char *p = strchr("aeiouAEIOU", ch); // search for a match
return p && *p; // If p is not NULL, and does not point to \0
}
int count_consonants(const char str[]) {
int count = 0;
while (*str != '\0') { // while not at end of string ...
char ch = *str++; // Get character and advance
count += isalpha((unsigned char) ch) && !my_isvowel(ch);
}
return count;
}
If you look for number of consonants, simply best count consonants instead of other things
#include <stdio.h>
#include <string.h>
int main (int narg,char*args[]){
char cons[ ] = "ZRTPQSDFGHJKLMWXCVBN";
char sentence[ ] = "This is my sentence!";
int i=0;
int sum_cons = 0;
for (i = 0; i < strlen(sentence); ++i)
if (strchr(cons,strupr(sentence)[i])) sum_cons++;
printf ("#CONS>%i\n",sum_cons);
return 0;
}