The code accepts a character string str as parameter, finds the largest character from the string, and moves it to the beginning of the string.
Example 1 (Single instance of large char)
Input: adebc
Output:eadbc
Example 2 (Multiple instance of large char)
Input: agfcdeg
Output:gafcdeg
Code
void maxCharToFront(char *str)
{
int large, i = 0;
char first;
large = str[i];
/* Find largest character */
while (str[i] != '\0')
{
if ((str[i] >= 'a' && str[i] <= 'z') ||
(str[i] >= 'A' && str[i] <= 'Z'))
{
if (str[i] > large)
{
large = str[i];
}
}
i++;
}
for(int i = 0; i < strlen(str); i++)
str[i] = str[i+1];
/*Move largest character to the front*/
first = str[0];
str[0]=large;
str[1] = first;
}
However instead of moving the largest char to the front it and leaving the rest intact, my code merely replaces the first character with the code.
Input: adebc
Current output:eebc
How do I improve this?
Consider the following suggestions:
You just need to store the position of largest char.
2nd for loop does not always need to loop till the end of the string.
You don't need to swap the first and largest char since you have adjusted the string, you can directly store the largest char in 0th location.
Sample code
void maxCharToFront(char *str)
{
int i = 0;
int pos=0;
/* Find largest character */
while (str[i] != '\0')
{
if ((str[i] >= 'a' && str[i] <= 'z') ||
(str[i] >= 'A' && str[i] <= 'Z'))
{
if (str[i] > str[pos])
{
pos = i;
}
}
i++;
}
char large = str[pos];
for(int i = pos; i > 0; i--)
str[i] = str[i-1];
str[0] = large;
}
Related
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 have a problem with my homework. I need to count quantity of upper case and quantity of vowels in string. Unfortunately, it always returns number 0 which looks as it doesn't change in function. Everything works until this one.
Here is my code:
#include <stdio.h>
#include <conio.h>
#include <string.h>
char *StringChange(char *text, int *upper, int *chars);
int main(void) {
char text[40];
int upper, chars;
puts("Type a string");
gets(text);
StringChange(text, &upper, &chars);
puts("Change words to start with upper case and change white spece to *");
puts(text);
printf("Quantity of upper case in string: %d\n", upper);
printf("Quantity of vowels: %d", chars);
getch();
return 0;
}
char *StringChange(char *text, int *upper, int *chars) {
int i, length;
length = strlen(text);
for (i = 1; i <= length; i++) {
if (text[i - 1] == '*' && (text[i] >= 'a' && text[i] <= 'z')) {
text[i] = text[i] - 32;
}
if (text[i] == ' ') {
text[i] = '*';
}
if (text[i] >= 'A' && text[i] <= 'Z') {
*upper = *upper + 1;
/* *upper++; that also doesn't work */
}
if (text[i] == 'a' || text[i] == 'e' || text[i] == 'i' || text[i] == 'o' || text[i] == 'u' || text[i] == 'y') {
*chars = *chars + 1;
/* *chars++; that also doesn't work */
}
}
if (text[0] >= 'a' && text[0] <= 'z') {
text[0] = text[0] - 32;
}
return (text);
}
I tried your code and I do get non-zero results -- depending on the input, of course, so maybe you are only testing on strings that produce zero.
However, the results are not always correct. There are two problems I found in the code:
1) As pointed out in a comment, you should initialize upper and chars to 0.
2) You are starting the loop at index 1, not index 0. I think you did this so you could look at text[i-1] inside the loop, but it is causing you to exclude the first character from your totals. You should start the loop index and 0 and figure out a different way to handle it within the loop. (Hint - note that the first if within the loop and the one following the loop have similar conditions and the same body.)
There are multiple issues in your code:
you should never use gets().
the variables upper and chars are not initialized
the function StringChange make a special case of text[0] but does not update the counts for this initial byte.
you hard code the conversion of lowercase to uppercase for ASCII.
you should stop at the end of the string
all white space is not replaced, on whitespace followed by a lowercase letter.
uppercase vowels should be counted too.
Here is a modified version:
#include <stdio.h>
char *StringChange(char *text, int *upper, int *chars);
int main(void) {
char text[200];
int upper, vowels;
puts("Type a string");
if (fgets(text, sizeof text, stdin)) {
StringChange(text, &upper, &chars);
puts("Change words to start with upper case and change white space to *");
puts(text);
printf("Quantity of upper case in string: %d\n", upper);
printf("Quantity of vowels: %d\n", vowels);
}
getchar();
return 0;
}
char *StringChange(char *text, int *upper, int *vowels) {
int i, at_start = 1;
*upper = *vowels = 0;
for (i = 0; text[i] != '\0'; i++) {
char c = text[i];
if (at_start && c >= 'a' && c <= 'z') {
c += 'A' - 'a';
text[i] = c;
}
if (c == ' ') {
c = '*';
text[i] = c;
at_start = 1;
} else {
at_start = 0;
}
if (c >= 'A' && c <= 'Z') {
(*upper)++; // *upper++ would just increment the pointer, leading to undefined behavior
}
if (strchr("aeiouyAEIOUY", c) {
(*vowels)++;
}
}
return text;
}
I'm trying to check if a sentence is palindrome or not. Neither space nor punctuation matter.
Examples:
• Never odd or even
• A man a plan a canal Panama.
• Gateman sees name, garageman sees name tag
Netheir of this sentences passes true on my code.
On my first for I try to remove spaces, punctuation and transform upper letters in lower.
int palindrome(char *str){
int n,n2 = 0,i,j=0;
n = sizeof(str)/sizeof(char);
char nova[n];
for (i=0;i< n;i++){
if(str[i] >= 'A' && str[i] <= 'Z'){
nova[n2] = ('a' + str[i] - 'A');
n2++;
}
else if(str[i] >= 'a' && str[i] <= 'z'){
nova[n2] = str[i];
n2++;
}
}
i=0;
while (i < n2-1){
if (nova[i]!= nova[j]){
return 0;
}
i++;
j--;
}
return 1;
}
line 4: you want to get the count of elements by sizeof.
But if you transfer your arguments to function by pointer.
n = sizeof(str)/sizeof(char);
n will always be 4 (on 32 bit platforms). Instead, use
n = strlen(str)
(need to #include <string.h>) if it is a string format in c.
The existing answer is good, but there is another way to solve this problem, without using additional allocated memory. You don't really need to store the letters anywhere in order to compare them - you can use pointers to your original string.
int palindrome(char *str)
{
int i = 0, j = strlen(str);
while (i < j)
{
if (str[j] == '\0' || !isalpha(str[j]))
--j; // skip the character on the right if it's not a letter
else if (!isalpha(str[i]))
++i; // skip the character on the left if it's not a letter
else if (tolower(str[i]) != tolower(str[j]))
return 0; // letters are different? - not a palindrome
}
// all letters were equal? - a palindrome
return 1;
}
Ok, now with all the modifications it works. Thanks guys.
int palindrome(char *str)
{
int n =0,i=0,j;
char nova[100];
while(str[i]!= '\0'){
if(str[i] >= 'A' && str[i] <= 'Z'){
nova[n] = ('a' + str[i] - 'A');
n++;
}
else if(str[i] >= 'a' && str[i] <= 'z'){
nova[n] = str[i];
n++;
}
i++;
}
i=0;
j= n-1;
while (i< j){
if (nova[i]!= nova[j]){
return 0;
}
i++;
j--;
}
return 1;
}
I had received this assignment last month and ended up getting it wrong because of the problem I will state after this. Currently, I am doing Caesar's Cipher and I believe I have the right format. I ask the user for a string and I encrypted with a key == 3. However, I want to loop around the alphabet if the plaintext letter is X, Y, Z, x, y, or z. But, when I put those any of those characters in, I do not get A, B, and C, but ]... and other braces. Any hints to fix the problem.
Thank you!
void main()
{
int key = 3;
char string[256];
int i = 0;
printf("Enter the string you want encrypted\n");
fgets(string, sizeof(string), stdin);
for (i = 0; i < strlen(string); i++) {
if (string[i] == ' ') {;}
else if ((string[i] >= 'a' && string[i] <= 'z' || string[i] >= 'A' && string[i] <= 'Z')){
string[i] = string[i] + key;
}
}
printf("Cipher text:%s",string);
}
You need to look at the ASCII table: http://www.asciitable.com/. You're using an ASCII encoding of the characters.
Z has a decimal value of 90, so 93 is ']'. You need to manually wrap back around to the beginning of the alphabet. This is best done with a modulo and adding the ASCII value of the first alphabetic character. It's up to you how you wrap capital letters (back to 'a' or to 'A').
You need to convert the character to its position in the alphabet, then find the result modulo 26 (alphabet length), then convert it back to the character. Something like:
char base = 0;
if(string[i] >= 'a' && string[i] <= 'z'){
base = 'a';
}else if(string[i] >= 'A' && string[i] <= 'Z'){
base = 'A';
}
if(base){
string[i] = ((string[i] - base) + key) % 26 + base;
}
You almost got it:
#include <stdio.h>
#include <string.h>
int main() {
char string[256];
int i = 0;
int key = 3;
const int num_letters = 26;
printf("Enter the string you want encrypted\n");
fgets(string, sizeof(string), stdin);
for (i = 0; i < strlen(string); i++) {
if (string[i] >= 'a' && string[i] <= 'z') {
string[i] = 'a' + (string[i] - 'a' + key) % num_letters;
}
else if (string[i] >= 'A' && string[i] <= 'Z') {
string[i] = 'A' + (string[i] - 'A' + key) % num_letters;
}
}
printf("Encrypted: %s\n", string);
return 0;
}
Enter the string you want encrypted
Zorro
Encrypted: Cruur
In C you can use the modulo operator % to wrap around, as shown above. Good luck!
The new string should contain only the alphabetic characters from the existing string in the same order. Non-alphabetic characters should be not be copied. If s is a null pointer, return a null pointer.
Example input:
"Ready... aim... fire!"
Output:
Readyaimfire
I don't know why in my first for loop, the code never enters the if statement. I'm also not sure if I allocated the memory for the new string correctly. Thanks for any help :)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *alphabetic (const char *s);
char *alphabetic (const char *s)
{
char *newChar;
int i;
char n = 0;
long length = strlen(s);
for(i=0; i<length; i++)
{
if( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
{
n++;
}
}
newChar = (char*)malloc(sizeof(char)*n);
for(i=0; i<length; i++)
{
if( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
{
newChar[i] = s[i];
}
}
return newChar;
}
int main (void)
{
char *a, *b, *c;
a = alphabetic ("Ready... aim... fire!");
b = alphabetic ("***");
c = alphabetic ("*a*b*c*");
printf ("%s\n", a);
printf ("%s\n", b);
printf ("%s\n", c);
free(a);
free(b);
free(c);
return 0;
}
The conditional of the first if and the conditional of the second if are such that if one is true then the other is false. Hence, you never get to the line
n++;
You need
if ( (s[i] <= 122 && s[i] >= 97) || (s[i] <= 90 && s[i] >= 65) )
To make the code more readable, you can make it:
if ( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
If you have the option of using the standard library, you can just use:
if ( isalpha(s[i]) )
BTW, the line
s = s + i;
is going to mess things up. As you iterate through the loop, you'll end up skipping parts of the input string. Remove that line.
You Can use a single loop of that
int j = 0; //take integer variable
for(i=0; i<length; i++)
{
if( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
{
//n++; //Remove this
newChar[j] = s[i];
j++;
}
}
Things about your code:
n should be n+1 to accommodate '\0' character
2nd for loop: you need to have another variable say j =0 and incremented on every match. You can't use i for the newChar array as in the original array s,since i might point to an address that's outof bounds in the newChar array.For ex: ready...aim, newchar # elements 8 while s =11
So saying newChar[8]=s[8] is wrong,rather it should be newChar[5]=s[8].
Posting the corrected code:
char *alphabetic (const char *s)
{
char *newChar;
int i,j=0; //Change1: extra variable j to keep a track of elements for newChar
char n = 0;
long length = strlen(s);
for(i=0; i<length; i++)
{
if( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
{
n++;
}
}
newChar = (char*)malloc(sizeof(char)*(n+1)); // Change2: n+1 instead of n
for(i=0; i<length; i++)
{
if( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
{
newChar[j++] = s[i]; //Change3: j instead of i
}
}
newChar[j]='\0'; //Termination of strings
return newChar;
}
I can't tell you why your code doesn't enter the if statement because you didn't provide the test case (input data) on which the algorithm does not enter the if statement. What I can tell you is that it won't do what you want it to do. Let's break down the for loop for a moment here:
it says "make variable i = 0, then, while i is smaller then the length of char array s, do some stuff then increment i". This is a very handy way to parse a char array. That's just fine and dandy, but inside the for loop, the first instruction is s = s + i. What that will do is move the pointer s forward by i characters at each iteration. Keep in mind that i will increase with time. Say we give that function the char * "This is a sentence.". The function strlen(s) will return 19 (which will be stored in length) and thus the for loop will iterate 19 times, with i taking values from 0 to 18 including. Let's see what's happening to s in there. First time, *s value is T. When you make s = s + i (i = 0), *s will still be T. T's ascii code is 84 and the if checks for values between 97 and 122 (including). So that's that for the first iteration. Then i becomes 1. And s moves one position further, thus *s will be 'h'. The ASCII code for the letter h is 104, so it enters the first if (because it is beween 122 and 97). Then, you ask if s[i] is beween 90 and 65. Now, because you incremented s, *s is 'h', but i == 1 at this point and thus s[i] is actually 'i' (whose ASCII code is 105 and thus never entering that loop). So if you wanna increment your n with your given algorithm I would say you need an input test case looking like so: "ThIsiSaSENtENCE". What you want is a clean string parsing for loop with another clean if to check whether the current character is a letter:
for(i = 0; i < length; i++)
{
if((s[i]<='Z' && s[i] >= 'A') || (s[i]<='z' && s[i]>='a'))
n++;
}
This will count how many letters are there in your char array s.
EDIT:
If you wanna remove those characters which are not letters and return the new string then you might wanna try something like this (NOT OPTIMAL):
char *copyStringByLetter(char *arg, int size)
{
int i = 0;
int n = 0;
for(i = 0; i < size; ++i){
if((s[i]<='z' && s[i]>='a')||(s[i]<='Z' && s[i]>='A'))
n++;
}
char *result = malloc(n+1); //need #include <stdlib.h>
if(!result){
fprintf(stderr, "Error alocating memory!");
exit(EXIT_FAILURE) //you need #include <stdlib.h> for this
}
int j = 0;
for(i = 0; i < size; i++){
if((s[i]<='z' && s[i]>='a')||(s[i]<='Z' && s[i]>='A')){
result[j] = s[i];
j++;
}
}
result[j] = '\0' //terminate the array
return result;
}
If you want to ask me why I am sending the length of char array as an argument, it is to prevent char overruns (who happen more often than you might think)