'toupper' and 'tolower' have no effect on char array in C - c

I am creating a function that creates a username. The user is asked for first name then last name. The last name is concatenated to the first letter of the first name. Also, any upper case letter should be transformed into lowercase letters. So input 'John DoE' should equal 'jdoe'.
Another function counts the number of lowercase letters in the string "THiS SentENCE HAS SOMe LoWEr CASE ChARAcTERs". Lower case letters are then converted to upper case and the string is printed.
The first function will not convert the uppercase letters to lowercase. The second function does not even recognize the ASCII value of any character.
I've tried using pointers for the two functions but there was no change in output.
void createUsername()
{
int j = 1;
char firstName[15], lastName[15], userName[20];
printf("Enter your first name : ");
fgets(firstName, 15, stdin);
firstName[strlen(firstName) - 1] = '\0';
printf("Enter your last name : ");
fgets(lastName, 15, stdin);
lastName[strlen(lastName) - 1] = '\0';
userName[0] = tolower(firstName[0]);
for (int i = 0, j; lastName[i] != '\0'; i++, j++)
userName[j] = tolower(lastName[i]);
userName[j+1] = '\0';
printf("User name : %s", userName);
}
void lowerToUpperCase()
{
char sentence[] = "THiS SentENCE HAS SOMe LoWEr CASE ChARAcTERs";
int lowerCases = 0;
for (int i = 0; sentence[i] != '\0'; i++)
{
if ((sentence[i] >= 97) && (sentence[i] <= 122))
{
lowerCases++;
sentence[i] = toupper(sentence[i]);
}
}
printf("Number of lower case characters= %d \n", lowerCases);
printf("Upper case sentence : %s \n", sentence);
}
expected output of Joe SMITH should be jsmith. The number of lower case letters should be 10 and the sentence should print all uppercase.
The actual output gives JSMITH, the number of lowercase letters is 0 and the sentence prints the original.

Lets start with simple things and we will go from there:
You can easily compare a with sentence[i]. Do this:
if ((sentence[i] >= 'a') && (sentence[i] <= 'z'))
{
lowerCases++;
sentence[i] = toupper(sentence[i]);
}
than comes this bit:
i < lastName[i] != '\0'
What the hell on earth is this? If you take a look at this page:
https://en.cppreference.com/w/c/language/operator_precedence
you will see that < has precedence over !=.
EDIT:
for (int i = 0, j; lastName[i] != '\0'; i++, j++)
j is reinitialized here as local variable for for() loop so it might get 0 but in my case it always got some garbage and setfault. So put this:
for (int i = 0; lastName[i] != '\0'; i++, j++)
and you will be set to go.

Apart from the problems mentioned in other answers, you also have problems with memory overwrites. Typing names longer than the buffers cause great pain in production. Better allocate enough memory on the fly to accommodate the names.
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void createUsername() {
printf("Enter your first name : ");
char *firstName;
errno = 0;
int n = scanf("%ms", &firstName);
if (n != 1) {
perror("scanf");
exit(EXIT_FAILURE);
}
printf("Enter your last name : ");
char *lastName;
errno = 0;
n = scanf("%ms", &lastName);
if (n != 1) {
perror("scanf");
free(firstName);
exit(EXIT_FAILURE);
}
char *userName = (char *) malloc(1u + strlen(lastName) + 1u);
userName[0] = tolower(firstName[0]);
char *userNameIter = userName + 1;
char *lastNameIter = lastName;
while ((*userNameIter = tolower((unsigned char) *lastNameIter))) {
userNameIter++;
lastNameIter++;
}
printf("User name : %s\n", userName);
free(userName);
free(lastName);
free(firstName);
}
void lowerToUpperCase() {
char sentence[] = "THiS SentENCE HAS SOMe LoWEr CASE ChARAcTERs";
int lowerCases = 0;
for (int i = 0;; i++) {
unsigned char const ch = (unsigned char) sentence[i];
if (islower(ch)) {
lowerCases++;
sentence[i] = toupper(ch);
} else if (ch == '\0') {
break;
}
}
printf("Number of lower case characters = %d\n", lowerCases);
printf("Upper case sentence : %s\n", sentence);
}

Related

Program to remove all non duplicate characters from a string

The following code I found on tutorialgateway is used to remove all duplicate characters from a string.
#include <stdio.h>
#include <string.h>
int main()
{
char str[100];
int i, j, k;
printf("\n Please Enter any String : ");
gets(str);
for(i = 0; i < strlen(str); i++)
{
for(j = i + 1; str[j] != '\0'; j++)
{
if(str[j] == str[i])
{
for(k = j; str[k] != '\0'; k++)
{
str[k] = str[k + 1];
}
}
}
}
printf("\n The Final String after Removing All Duplicates = %s \n", str);
return 0;
}
I thought if I changed the == for != on the if statement it would instead remove all unique or non duplicate characters, but instead it does something else. What am I not understanding about how this code works?
Your solution will take approximately O(n^3).
Also, having three nested loops adds needless complexity.
If we change the algorithm to use a frequency table, we can reduce complexity. And, we can reduce the running time to 2*O(n) or O(n).
Side note: Never use gets. See: Why is the gets function so dangerous that it should not be used?
Here is the refactored code:
#include <stdio.h>
#include <string.h>
int
main()
{
char str[100];
char freq[256] = { 0 };
char *src;
char *dst;
unsigned char chr;
printf("\n Please Enter any String : ");
fgets(str,sizeof(str),stdin);
str[strcspn(str,"\n")] = 0;
printf("\n The Original String = %s \n", str);
// get frequency count
src = str;
for (chr = *src++; chr != 0; chr = *src++) {
switch (freq[chr]) {
case 0: // new [unique] char
freq[chr] = 1;
break;
default: // duplicate
freq[chr] = 2;
break;
}
}
dst = str;
src = str;
// copy over chars that are unique
for (chr = *src++; chr != 0; chr = *src++) {
if (freq[chr] == 1)
*dst++ = chr;
}
*dst = 0;
printf("\n The Final String after Removing All Duplicates = %s \n", str);
return 0;
}
Here is the program output:
Please Enter any String :
The Original String = abbbbbbbbbccdefghe
The Final String after Removing All Duplicates = adfgh

Can C presume which array I want to store my characters?

I'm writing code which checks if an array is palindrome or not:
Write a program that reads a message, then checks whether it's a palindrome
(the letters in the message are the same from left to right as from right to left):
Enter a message: He lived as a devil, eh?
Palindrome
Enter a message: Madam, I am Adam.
Not a palindrome
When I have entered He lived as a devil, eh?,
it gives me the output Not a palindrome,
but the real output should be palindrome.
Below code is what I have tried so far.
#include <stdio.h>
#include <ctype.h>
#define MAX_LEN 100
int main(void) {
char message[MAX_LEN];
char c, *p = message, *q;
printf("Enter a message: ");
while ((c = toupper(getchar())) != '\n' & p < message + MAX_LEN) {
if (isalpha(c))
*p++ = c;
}
p--;
for (q = message; q < p; q++, p--) {
if (*p != *q) {
printf("Not a palindrome\n");
return 0;
}
}
printf("Palindrome\n");
return 0;
}
For starters you should declare the variable c as having the type int. The user can interrupt the input process in which case the function getchar returns integer value EOF and you should check whether this occurred.
char *p = message, *q;
int c;
There is a bug in the condition of the while statement
while ((c = toupper(getchar())) != '\n' & p < message + MAX_LEN) {
Instead of the bitwise operator & you have to use the logical AND operator &&.
As I already have said you should check in the condition of the while statement whether the user interrupted the input. For example
while ( p < message + MAX_LEN && ( c = toupper(getchar())) != EOF && c != '\n') {
if (isalpha(c))
*p++ = c;
}
The argument of a call of toupper or isalpha should be converted to the type unsigned char. Otherwise in general without the casting such a call can invoke undefined behavior.
It is desirable not to exclude from an entered string numbers. SO it is better at least to call the function isalnum instead of the function isalpha.
The user can enter an empty string in this case this decrement of the pointer
p--;
also can invoke undefined behavior.
And it is better when a program has one point to exit.
The program can look the following way
#include <stdio.h>
#include <ctype.h>
#define MAX_LEN 100
int main(void)
{
char message[MAX_LEN];
printf( "Enter a message: " );
char *p = message;
for ( int c; p < message + MAX_LEN && ( c = getchar() ) != EOF && c != '\n'; )
{
if( isalnum( ( unsigned char )c ) )
{
*p++ = toupper( ( unsigned char )c );
}
}
int palindrome = 1;
if ( p != message )
{
for ( char *q = message; palindrome && q < --p; ++q )
{
palindrome = *q == *p;
}
}
printf( "The entered message is %spalindrome\n",
palindrome ? "" : "not " );
return 0;
}
Its output might look for example like
Enter a message: He lived as a devil, eh?
The entered message is palindrome
or like
Enter a message: Madam, I am Adam
The entered message is not palindrome
Pay attention to that instead of using a loop with numerous calls of the function getchar you could use only one call of the function fgets
fgets( message, sizeof( message ), stdin );
or
if ( fgets( message, sizeof( message ), stdin ) != NULL )
{
// check whether the entered string is a palindrome
}
Before check the palindrome you have to remove white spaces and punctuation marks. For an example if you use civic?, it is not palindrome because of ?. In the other hand if you use civ ic, it is not palindrome because of white space. There for
Convert all letters to uppercase or lowercase.
Remove white spaces.
remove punctuation marks.
Check palindrome or not.
You can do it by using # include <string.h>
First thing is you have to use scanf() which accept string with white space.
printf("Enter a string = ");
scanf("%[^\n]%*c", word);
Then you have to convert that string to Uppercase or Lowercase because a != A. We know civic is a palindrome but Civic is not a palindrome('Civic != civiC) because Uppercase letters have different ASCII values and Lowercase letters have different ASCII values.
(a - z) -: 97 - 122
(A - Z) -: 65 - 90
In my case I have converted lowercase to uppercase.
while(strlen(word) >= i)
{
if(word[i] >= 97 && word[i] <= 122)
{
word[i] = word[i] - 32;
}
i++;
}
Another case is your if you enter civ ic with white space, it's palindrome word is ci vic. You can see civ ic != ci vic. There for you have to remove white spaces in your program. And also you have to remove punctuation marks because if you use civic, it's reversed word is ,civic'. You can seecivic, != ,civic`.
int len = strlen(word);
while(a < len)
{
for(i = 0; i < len; i++)
{
if(word[i] == ' ' || !(word[i] >= 'A' && word[i] <= 'Z'))
{
for(j = i; j < len; j++)
{
word[j] = word[j+1];
}
len--;
}
}
a++;
}
Final thing is we have to revers our string and need to check if our reversed string is equal to our original string. If it is true our String is palindrome. If it is false our String is not a palindrome.
for(i = 0; i < len; i++)
{
if(word[i] == word[len - 1])
{
len--;
}
else
{
printf("%s is not a palindrome\n", word);
return 0;
}
}
printf("%s is a palindroeme\n", word);
This the full code after you merging above parts
# include <stdio.h>
# include <string.h>
int main (void)
{
char word[100];
int i = 0;
int j, x = 0;
int a = 0;
printf("Enter a string = ");
scanf("%[^\n]%*c", word);
while(strlen(word) >= i)
{
if(word[i] >= 97 && word[i] <= 122)
{
word[i] = word[i] - 32;
}
i++;
}
printf("After converting it to uppercase = %s\n", word);
int len = strlen(word);
while(a < len)
{
for(i = 0; i < len; i++)
{
if(word[i] == ' ' || !(word[i] >= 'A' && word[i] <= 'Z'))
{
for(j = i; j < len; j++)
{
word[j] = word[j+1];
}
len--;
}
}
a++;
}
printf("After removing spaces = %s\n", word);
for(i = 0; i < len; i++)
{
if(word[i] == word[len - 1])
{
len--;
}
else
{
printf("%s is not a palindrome\n", word);
return 0;
}
}
printf("%s is a palindroeme\n", word);
return 0;
}
First test Output -:
Enter a string = He lived as a devil, eh?
After converting it to uppercase = HE LIVED AS A DEVIL, EH?
After removing spaces = HELIVEDASADEVILEH
HELIVEDASADEVILEH is a palindroeme
Second test Output -:
Enter a string = Madam I am Adam.
After converting it to uppercase = MADAM I AM ADAM.
After removing spaces = MADAMIAMADAM
MADAMIAMADAM is not a palindrome

I want my code to print the frequency of characters in the order of appearance of string

My code is printing the frequency of characters in random order. What can be done so that it prints the frequency of characters in order in which the word is given. My current code is as follows
#include <stdio.h>
#include <conio.h>
void main() {
char string1[50];
int i = 0, counter[26] = { 0 };
printf("\nEnter a string\n");
//Inputs a string
gets(string1);
while (string1[i] != '\0') {
//checks and includes all the characters
if (string1[i] >= 'a' && string1[i] <= 'z') {
//counts the frequency of characters
counter[string1[i] - 'a']++;
i++;
}
}
//printing frequency of each character
for (i = 0; i < 26; i++) {
if (counter[i] != 0)
printf("%c occurs %d times.\n", i + 'a', counter[i]);
}
getch();
}
sample output:
There are several issues in your code:
you use gets: this function is unsafe, it was removed from the current version of the C Standard.
you increment i only for if string1[i] is a lowercase letter: you will run an infinite loop if you type any other character.
the proper prototype for main is either int main(void) or int main(int arc, char *argv[]).
you only count lower case letters. H is upper case, thus not counted.
Here is an improved version:
#include <stdio.h>
#include <ctype.h>
int main(void) {
char string1[128];
int i = 0, counter[256] = { 0 };
printf("\nEnter a string\n");
//Inputs a string
if (fgets(string1, sizeof string1, stdin) == NULL) {
// empty file: got an empty line
*string1 = '\0';
}
for (i = 0; string1[i] != '\0'; i++) {
if (isalpha((unsigned char)string1[i])) {
//counts the frequency of letters
counter[string1[i]]++;
}
}
//printing frequency of each counted character
//characters are printed in the order of appearance
for (i = 0; string1[i] != '\0'; i++) {
if (counter[string1[i]] != 0) {
printf("%c occurs %d times.\n",
string1[i], counter[string1[i]]);
counter[string1[i]] = 0; // print each letter once.
}
}
getch();
return 0;
}
You can get the characters printed in order of their appearance by using the string a second time to generate the output.
In your section where you are "printing the frequency of each character", use the code to process the input string. This time, if the frequency value is not zero, print it and then reset the frequency value to zero. If the frequency value is zero, you must have already printed it so do nothing.
//printing frequency of each counted character (in input order)
for (i = 0; string1[i] != '\0'; i++) {
char ch = string[i];
if (counter[ch - 'a'] != 0) {
printf("%c occurs %d times.\n", ch, counter[ch - 'a']);
counter[ch - 'a'] = 0;
}
}

word length statistic C language

Can anyone help me to make that project.
Write a program that calculates statistics on word length for a sentence. The sentence isterminated by a ’.’ For each found length of a word the number of words of that length
is printed. Only those lengths that are found in the input are printed. Only letters from
a-z or A-Z are allowed to form words. Words are separated by a space. No punctuation
characters other than ’.’ are allowed. If any other input character is recognized or the
input is longer than 80 characters the program displays ”NOT VALID” (see Hints). Note,
that in the case that no word is present in the input, nothing is printed.
% u6_stats
Enter a sentence: Bolt was expected to use the super bark.
Length 2: 1
Length 3: 3
Length 4: 2
Length 5: 1
Length 8: 1
% u6_stats
Enter a sentence: Something wasn’t right.
NOT VALID
#include <stdio.h>
#include <conio.h>
void main() {
char s[100];
int numOfWords, lengthOfWord = 0;
int i = 0, j = 0;
printf("Enter the text : ");
fgets(s, sizeof(s), stdin);
numOfWords = 1;
while(s[i]!='\0') {
if(s[i] == ' ')
numOfWords++;
i++;
}
//printf("%d", numOfWords);
i = 0;
int help[numOfWords];
int l;
for(l = 0; l < numOfWords ; l++)
help[l] = 0;
while(s[i]!='\0') {
if(s[i] != ' ' && s[i] !='\n' && s[i]!='.' ) {
lengthOfWord++;
i++;
}else{
help[j] = lengthOfWord;
j++;
lengthOfWord = 0;
i++;
}
}
int repeat[80];
for(l = 0; l < 80 ; l++)
repeat[l] = 1;
int num = 1;
i=0,l=0;
for(i = 0;i<numOfWords;i++) {
for(l=i+1;l<numOfWords;l++)
if(help[i]==help[l]) {
repeat[l]='\0';
num++;
repeat[i] = num;
}
num = 1;
}
l=0;
for (l=0; l<numOfWords; l++)
if (repeat[l]!='\0' && help[--l]!=help[++l])
printf("Length %d: %d\n", help[l],repeat[l]);
}
So, the problem is that if i inpute a text like"abc abcd abc abc"
the result will be like "length 3: 3 length 4: 1 length 3: 2".
So when the program already compared 1st (here 3) element with otheres, this element will not be comparing again, but i have the 3d element with same length, and it that case, the program compare it with remained elements and print 2. How can i rework my code, if i dont wont to compare already compared elements.
Second problem is that i need to get results from lowest length till highst.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
void invalid(void){
puts("NOT VALID");
exit(EXIT_FAILURE);
}
int main(void){
int length[80]={0};
int i, ch, word_len=0;
printf("Enter a sentence: ");
while(1){
ch=getchar();
if(isalpha(ch)){
++word_len;
} else if(ch == ' ' || ch == '.'){
if(word_len>80)
invalid();
if(word_len)
length[word_len-1]++;//-1: to 0 origin
if(ch == '.')
break;
word_len = 0;
} else {
invalid();
}
}
for(i=0;i<sizeof(length)/sizeof(*length);++i){
if(length[i])
printf("Length %d: %d\n", i+1, length[i]);
}
return 0;
}
A simple approach is with strtok (http://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm).
#include <stdio.h>
int numwords (char *str);
int main() {
char word[] = "This is a test - does it pass?";
int c = numwords(word);
printf("Words = %d\n", c);
return 0;
}
int numwords(char *str)
{
int n = 0;
for(str=strtok(str, " -.!,;"); str; str=strtok(NULL, " -.!,;"))
n++;
return n;
}

two dimensional array in c, reversing and storing a sentence

Hey I'm really new to programming and having trouble with arrays. Can someone help me with this project. "c programming a modern approach: modify a program that reverses the words of a sentence so that it stores the words in a two dimensional char array as it reads the sentence, with each row of the array storing a single word. assume that the sentence contains no more than 30 words and no word is more than 20 characters long. Be sure to store a null character at the end of each word so that it can be treated as a string"
(also i don't get what its saying about the null character).
here's my try but it's not working. i think i'm close though.
#include <stdio.h>
#define MAX_SENTENCE_LEN 80
#define SENTENCE_MAX 30
#define WORD_MAX 20
int main(void)
{
char ch, sentence[MAX_SENTENCE_LEN] = {' '}, terminator = '.';
int n, i, j, start, finish;
printf("Enter a sentence: ");
for (n = 1; n < MAX_SENTENCE_LEN; n++) {
ch = getchar();
if (ch == '.' || ch == '?' || ch == '!') {
terminator = ch;
break;
}
sentence[n] = ch;
}
printf("Reversal of sentence:");
finish = n;
for (start = finish - 1; start >= 0; start--) {
if (sentence[start] == ' ') {
for (i = start; i < finish; i++)
putchar(sentence[i]);
finish = start;
}
{
int sentence[SENTENCE_MAX][WORD_MAX];
int word[30][20];
for (i=0; i< SENTENCE_MAX;i++){
for (j=0; j<WORD_MAX; j++)
sentence[i][j]=-1;
}
}
}
printf("%c\n", terminator);
return 0;}
i wrote a new code which i think is closer to what i want but it still won't run. do i have a faulty compiler or what?
anyway here's the new code
#include<stdio.h>
#define N 100
int main (void)
{
char sentence[N][N], ch, termChar;
int i = 0, l = 0, count = 0;
int j = 0, k, start, finish, word;
printf("enter a sentence: ");
while (ch = getchar())
{
sentence[i][l++]= ch;
if (ch == ' ')
{
sentence[i][l] = '\0';
i++;
l = 0;
count++;
}
if (ch == '.' || ch == '!' || ch == '?')
{
sentence[i][l-1]= ' ';
sentence[i][l]= '\0';
termChar = ch;
count ++;
break;
}
}
for(i=count ; i>=0; i--)
printf("%s ", sentence[i]);
printf("%c\n", termChar);
return 0;
}
Your code worked perfectly in my environment (Windows, C99 compiler, 32bit build). I entered a short sentence, and it reversed it:
Regarding: i don't get what its saying about the null character
a C string is defined by a null character: \0, at the end of a char array. example char string[]="word" looks like: |w|o|r|d|\0| in memory.
Without the \0, it would simply be a char array, but not a string, and would therefore not be useable in any of the string functions such as strcpy(), strlen(), etc.
By the way, sentence creation and initialization:
char sentence[MAX_SENTENCE_LEN] = {' '};
Does not guarantee contents for the entire length of the char array.
This may be the reason your environment is not running your code, while my environment does.
Depending on compiler, OS, and other random factors, sentence could be filled with anything. So, if your code is not running on your machine, it is likely that you just need to initialize sentence to \0. Replace that line with these:
char sentence[MAX_SENTENCE_LEN]; //create
memset(sentence, 0 ,MAX_SENTENCE_LEN); //zero all memory
sentence[0]=' '; //set first char to a space (' '). (not sure why)
Also by chance, if the user input results in string length == MAX_SENTENCE_LEN, then your program will crash as there is only enough room in sentence for MAX_SENTENCE_LEN-1 + \0.
#include <stdio.h>
#define MAX_SENTENCE_LEN 80
#define SENTENCE_MAX 30
#define WORD_MAX 20
int main(void){
char ch, sentence[MAX_SENTENCE_LEN] = {' '}, terminator = '.';
int n, i, j, start, finish;
char word[SENTENCE_MAX][WORD_MAX+1];
int wc=0, wcc=0;
printf("Enter a sentence: ");
for (n = 1; n < MAX_SENTENCE_LEN; n++) {
ch = getchar();
if (ch == '.' || ch == '?' || ch == '!') {
terminator = ch;
break;
} else if(ch != ' '){
word[wc][wcc++] = ch;
} else if(ch == ' '){//this is assumed to be one space between words.
word[wc++][wcc] = '\0';//null character
wcc = 0;
}
sentence[n] = ch;
}
word[wc++][wcc] = '\0';
printf("Reversal of sentence:");
finish = n;
for (start = finish - 1; start >= 0; start--) {
if (sentence[start] == ' ') {
for (i = start; i < finish; i++)
putchar(sentence[i]);
finish = start;
}
}
printf("%c\n", terminator);
for(i=wc-1;i>=0;--i){
printf("%s", word[i]);
if(i>0)
putchar(' ');
}
printf("%c\n", terminator);
return 0;
}

Resources