Counting the number of vowels in a string in C - arrays

enter image description here
I'm solving the decryption problem in C language
There's a problem.
There's a process of counting the vowels in the string,
code not reading the number of vowels properly in that 'countingmeasure'
I was so curious that I debugged it,
count ++ doesn't work at'o'.
I'm really curious why this is happening
#include <stdio.h>
int main(void)
{
char original[15] = { 't','f','l','e','k','v','i','d','v','r','j','l','i','v',NULL };
printf("암호화된 문자열 : %s\n", original);
printf("원본 가능 문자열 \n");
printf("\n");
for (int j = 0; j < 26; j++)//모음이 7개일때만 출력을 어떻게 시킬까?
{
char change[14] = { 0 };
int counter=0;
char a;
for (int i = 0; i < 14; i++)
{
a = original[i] + j;
if (a > 122)
{
original[i] -= 26 ;
}
if (a == 'a' || a == 'e' || a == 'i' || a == 'o' || a == 'u')
{
counter++;
}
printf("%c", original[i] + j);
}
printf(" %d\n",counter);
}
}

a = original[i] + j; doesn't make any sense, since a is a char and the result might not fit inside it. Specifically, "character value + 26" might be larger than 127. Is char signed or unsigned by default?
Furthermore, arithmetic on any symbols except '0' to '9' isn't well-defined and they are not guaranteed to be allocated adjacently. Also please refrain from using hard-coded "magic numbers" in source code. Instead of 122 you should use 'z' etc.
There are several ways you can fix the program.
The quick & dirty solution is to do unsigned char a on the existing program, if you are content with "it just works, but I don't even know what I'm doing".
A better solution is to declare a string of vowels and then for every character in the input string, do a strchr() search in the vowel string for a match. (Correct but naive and slow, good enough beginner solution.)
A professional solution would be to create a look-up table of 128 booleans like
const bool LOOKUP [128] = { ['A'] = true, ['a'] = true, ['E'] = true, ... }; Then check if(item[i] == LOOKUP[ item[i] ]) /* then vowel */.

Use functions.
NULL is a pointer not zero or null terminating character
Use string literals.
use standard functions to change the case (tolower, toupper)
char *mystrchr(const char *str, const char lt, int ignoreCase)
{
while(*str)
{
if(ignoreCase)
if(tolower((unsigned char)*str) == tolower((unsigned char)lt)) return (char *)str;
else
if(*str == lt) return (char *)str;
str++;
}
return NULL;
}
size_t count(const char *haystack, const char *needle, int ignoreCase)
{
size_t count = 0;
while(*haystack)
{
if(mystrchr(needle, *haystack, ignoreCase)) count++;
haystack++;
}
return count;
}
int main(void)
{
char *str = "tflekvidvrjliv";
printf("%zu\n", count(str, "aeiou", 1));
}

Related

Replacing a sequence of ascending characters by ascii code with a specific pattern

I am doing some kind of challenge in C in the internet and got the following mission:
Given a string, that consists of some ascending characters one after the other (by ASCII value), return the same string, but replace the middle letters of the sequence with one minus sign
Example:
Given the following input: dabcefLMNOpQrstuv567zyx
We expect the following output: da-cefL-OpQr-v567zyx
The code I've tried:
/* Importing useful libs */
#include <stdio.h>
#include <string.h>
/* Declaring boolean definitions */
typedef enum {
false,
true
}
bool_enum;
/* Declaring Max. Input Length */
#define MAX_INPUT_LENGTH 80
void sequence_replace(char string[]);
/* Main Function */
int main() {
char input_str[MAX_INPUT_LENGTH];
printf("Please enter the string you'd like to switch its sequences with the three char method: ");
scanf("%s", input_str);
sequence_replace(input_str);
return 0;
}
void sequence_replace(char string[]) {
int first_char, last_char;
int slen = strlen(string);
bool_enum sequence = false;
for(int i = 0; i < slen; i ++) {
int s1 = string[i];
int s2 = string[i+1];
if (s1 + 1 == s2) {
if (sequence = false) {
sequence = true;
first_char = i;
}
}
if (s1 + 1 != s2) {
if (sequence = true) {
last_char = i;
string[first_char + 1] = '-';
for(int j = first_char+2; j < last_char; j++) {
string[j] = '';
}
}
sequence = false;
}
}
printf("Sequences after replacement are: %s", string);
}
Basically what I tried to do, is in the sequence_replace function iterate over the string until I find one character whose ascii code + 1 equals to the ascii code of the next character, I change a boolean flag to true to show that I am inside a sequence as well as keeping the index of when the first character of the sequence showed up, then once it hits a character whose ascii code - 1 is not equal to the previous character ascii code, I then switch the character that comes next after the first character with '-' sign and then just run a loop until the end of the sequence to replace all other remaining chars with just an empty string.
Unfortunately, doesn't seem to be working, Would like to get any help if possible.
For starters there is no need to introduce this typedef declaration
/* Declaring boolean definitions */
typedef enum {
false,
true
}
bool_enum;
It is much better just to include the header <stdbool.h> and use names bool, false and true defined in the header.
The function itself should be declared like
char * sequence_replace(char string[]);
Using the function strlen is redundant and inefficient.
As it follows from the provided example you should check whether a current character is an alpha character or not.
You may not declare integer character constants that do not contain a symbol like this
string[j] = '';
That is in C there are no empty integer character constants.
Also there is a logical error in this if statement (apart from the typo in the inner of statement if (sequence = true) { where there is used the assignment operator = instead of the equality operator ==)
if (s1 + 1 != s2) {
if (sequence = true) {
last_char = i;
string[first_char + 1] = '-';
for(int j = first_char+2; j < last_char; j++) {
string[j] = '';
}
}
sequence = false;
}
It unconditionally write the symbol '-' even if there are only two characters that satisfy the condition
s1 + 1 == s2
In this case according to the provided example the symbol '-' is not inserted.
Also for example the for loop will not process the tail of the string that represents an increased sequence of letters.
The function can look the following way as shown in the demonstration program below.
#include <stdio.h>
#include <ctype.h>
char * sequence_replace( char s[] )
{
char *p = s;
for ( char *q = s; *q; )
{
*p++ = *q++;
char *current = q;
while (isalpha( ( unsigned char )q[-1] ) &&
isalpha( ( unsigned char )q[0] ) &&
( unsigned char )( q[-1] + 1 ) == ( unsigned char )q[0])
{
++q;
}
if (current != q)
{
if (q - current > 1)
{
*p++ = '-';
}
*p++ = q[-1];
}
}
*p = '\0';
return s;
}
int main( void )
{
char s[] = "dabcefLMNOpQrstuv567zyx";
puts( s );
puts( sequence_replace( s ) );
}
The program output is
dabcefLMNOpQrstuv567zyx
da-cefL-OpQr-v567zyx

Ascii to integer using no library functions

My teacher gave us an assignment where we create a function that reads ASCII digit characters and converts them to a number without using any library functions such as atoi. Through some research i came up with this in my own file:
#include <stdio.h>
#include <sttdef.h>
int main() {
char testString[] = "123";
int convertedResult = 0;
int i;
for(i = 0; testString[i] != '\0'; i++){
convertedResult = convertedResult*10 + testString[i] - '0';
printf("%i\n",convertedResult);
if (testString[i] == '\0') {
break;
}
}
return 0;
}
While this works on its own i have to use the main file he gave us to call on this specific function.
char *asciiToInteger(char *inputString, int *integerPtr) {
return inputString;
}
I'm a bit confused as to how to proceed from here? attatched picture is main
#include <stdio.h>
#include <stddef.h>
char * asciiToInteger(char *inputString, int *integerPtr){
int convertedResult =0;
for(int i = 0; inputString[i] != '\0'; i++){
convertedResult = convertedResult*10 + inputString[i] - '0';
}
*integerPtr=convertedResult;
return inputString;
}
int main() {
char testString[] = "123";
int integerPtr;
asciiToInteger(testString, &integerPtr) ;
printf("%d\n",integerPtr);
return 0;
}
Your code has a couple of problems:
It assumes the entire string is digits
It checks for the end of string twice
I think a better implementation would be:
#include <stdio.h>
const char *asciiToInteger(const char *inputString, int *value)
{
int result = 0;
while (isdigit((unsigned int) *inputString))
{
result *= 10;
result += *inputString++ - '0';
}
*value = result;
return inputString;
}
This returns a pointer to the first non-converted character, which might be to the end of string marker if the string is all digits. I added const on the strings of course, since this converter is just reading from the strings.
When you get an assignment like this the first step is to make sure you understand what the function is supposed to do. Your question has no such description so that is the place to start.
From the behavior of the main function it seems to be something like:
If the first character in the input string is not a digit return NULL
If the first character in the input string is a digit convert all leading digits to an integer stored in the object pointed to by integerPtr and return a pointer to the character following the converted digits.
Examples:
inputString = "a123b67" --> return NULL
inputString = "123b67" --> *integerPtr = 123 and return a pointer to the 'b' in the input
That could look something like this:
char *asciiToInteger(char *inputString, int *integerPtr) {
if (*inputString < '0' || *inputString > '9')
return NULL; // no leading digit
*integerPtr = 0;
do
{
*integerPtr = *integerPtr * 10 + *inputString - '0';
++inputString;
} while (*inputString >= '0' && *inputString <= '9');
return inputString;
}
Notice that the code above can't handle negative integers.

How To Replace A Certain Character in C

I am writing a program that replaces characters in the user's input in C but I don't know how to replace the certain characters. Is there a certain method for C that replaces characters in a string? If you know python, then I want something a bit like this in python:
string.replace('certain_character','replacement_character')
Something like that, except for C, and not python.
This is my code that I have written so far:
#include <stdio.h>
int main(){
char str[BUFSIZ];
printf("Welcome To My Secret Language encoder!Enter some text: \n");
scanf("%s",str);
/*
Where I want to replace certain characters
*/
printf("Here is your text in secret language mode: %s \n",str);
}
I'm writing this code to learn C more, and that's why i'm not doing it in a higher level language like python.So, how do you replace certain characters in a string?
Nothing like that in C. You'll have to scan the string yourself:
#include <string.h>
char str[] = "I love cats";
int i;
for(i = 0; i < strlen(str); i++)
{
if(str[i] == 'c')
str[i] = 'b';
}
Now, if you're looking for a substring, you'll need something like strstr.
strchr finds the given character in a string, or returns NULL.
int main() {
int c;
while ( ( c = getchar() ) != EOF ) {
char const * found, * source = "abc", * dest = "xyz";
if ( ( found = strchr( "abc", c ) ) != NULL ) {
putchar( dest[ found - source ] );
} else {
putchar( c );
}
}
return 0;
}
If you have a lot of characters that you want to replace with other characters (like a Caesar cypher) you can build a lookup for yourself as follows:
#include <string.h>
char plain[] = "Hello there good people";
char encoder[26] = "ghijklmnopqrstuvwxyzabcdef";
char secret[100]; // long enough
int n = strlen(plain);
for(ii = 0; ii < n; ++ii) {
secret[ii] = encoder[(tolower(plain[ii]) - 'a')%26];
}
secret[n] = '\0';
This uses a couple of tricks:
cast all characters to lower case
subtract 'a' from the lowercase number - since a char is really just a number, we now have a == 0
Perform a modulo operation on the result so things that fall outside of the range of good characters don't cause a memory access error.
Add a '\0' at the end to make sure the string is properly terminated.
Copying things into a new string; obviously you could do an in-place replacement.
As written this will turn numbers (digits) and punctuation / symbols / spaces into characters. You could decide that anything that is not a letter is maintained - and maybe that only lower case letters are converted. In that case
#include <string.h>
char plain[] = "Hello there good people";
char encoder[26] = "ghijklmnopqrstuvwxyzabcdef";
char secret[100]; // long enough
int n = strlen(plain);
for(ii = 0; ii < n; ++ii) {
if(plain[ii] >= 'a' && plain[ii] <= 'z') {
secret[ii] = encoder[plain[ii] - 'a'];
}
else {
secret[ii] = plain[ii];
}
}
secret[n] = '\0';
there is no such function, you have to write one using strstr.
if you can use std::string, you can use string.replace()
Say you want to replace: A with z and b with X
char *replace(char *src, int replaceme, int newchar)
{
int len=strlen(src);
char *p;
for(p=src; *p ; p++)
{
if(*p==replaceme)
*p=newchar;
}
return src;
}
usage:
replace(string, 'A', 'z');
replace(string, 'b', 'X');
This is just the logic to do it, you need more statements in your code.

Effective way of checking if a given string is palindrome in C

I was preparing for my interview and started working from simple C programming questions. One question I came across was to check if a given string is palindrome. I wrote a a code to find if the user given string is palindrome using Pointers. I'd like to know if this is the effective way in terms of runtime or is there any enhancement I could do to it. Also It would be nice if anyone suggests how to remove other characters other than letters (like apostrophe comas) when using pointer.I've added my function below. It accepts a pointer to the string as parameter and returns integer.
int palindrome(char* string)
{
char *ptr1=string;
char *ptr2=string+strlen(string)-1;
while(ptr2>ptr1){
if(tolower(*ptr1)!=tolower(*ptr2)){
return(0);
}
ptr1++;ptr2--;
}
return(1);
}
"how to remove other characters other than letters?"
I think you don't want to actually remove it, just skip it and you could use isalpha to do so. Also note that condition ptr2 > ptr1 will work only for strings with even amount of characters such as abba, but for strings such as abcba, the condition should be ptr2 >= ptr1:
int palindrome(char* string)
{
size_t len = strlen(string);
// handle empty string and string of length 1:
if (len == 0) return 0;
if (len == 1) return 1;
char *ptr1 = string;
char *ptr2 = string + len - 1;
while(ptr2 >= ptr1) {
if (!isalpha(*ptr2)) {
ptr2--;
continue;
}
if (!isalpha(*ptr1)) {
ptr1++;
continue;
}
if( tolower(*ptr1) != tolower(*ptr2)) {
return 0;
}
ptr1++; ptr2--;
}
return 1;
}
you might need to #include <ctype.h>
How about doing like this if you want to do it using pointers only:
int main()
{
char str[100];
char *p,*t;
printf("Your string : ");
gets(str);
for(p=str ; *p!=NULL ; p++);
for(t=str, p-- ; p>=t; )
{
if(*p==*t)
{
p--;
t++;
}
else
break;
}
if(t>p)
printf("\nPalindrome");
else
printf("\nNot a palindrome");
getch();
return 0;
}
int main()
{
const char *p = "MALAYALAM";
int count = 0;
int len = strlen(p);
for(int i = 0; i < len; i++ )
{
if(p[i] == p[len - i - 1])
count++;
}
cout << "Count: " << count;
if(count == len)
cout << "Palindrome";
else
cout << "Not Palindrome";
return 0;
}
I have actually experimented quite a lot with this kind of problem.
There are two optimisations that can be done:
Check for odd string length, odd stings can't be palindromes
Start using vectorised compares, but this only really gives you performance if you expect a lot of palindromes. If the majority of your strings aren't palindromes you are still best off with byte by byte comparisons. In fact my vectorised palindrome checker ran 5% slower then the non-vectorised just because palindromes were so rare in the input. The extra branch that decided vectorised vs non vectorised made this big difference.
Here is code draft how you can do it vectorised:
int palindrome(char* string)
{
size_t length = strlen(string);
if (length >= sizeof(uintptr_t)) { // if the string fits into a vector
uintptr_t * ptr1 = (uintptr_t*)string;
size_t length_v /= sizeof(uintptr_t);
uintptr_t * ptr2 = (uintptr_t*)(string + (length - (length_v * sizeof(uintptr_t)))) + length_v - 1;
while(ptr2>ptr1){
if(*ptr1 != bswap(*ptr2)){ // byte swap for your word length, x86 has an instruction for it, needs to be defined separately
return(0);
}
ptr1++;ptr2--;
}
} else {
// standard byte by byte comparison
}
return(1);
}

C - Largest String From a Big One

So pray tell, how would I go about getting the largest contiguous string of letters out of a string of garbage in C? Here's an example:
char *s = "(2034HEY!!11 th[]thisiswhatwewant44";
Would return...
thisiswhatwewant
I had this on a quiz the other day...and it drove me nuts (still is) trying to figure it out!
UPDATE:
My fault guys, I forgot to include the fact that the only function you are allowed to use is the strlen function. Thus making it harder...
Uae strtok() to split your string into tokens, using all non-letter characters as delimiters, and find the longest token.
To find the longest token you will need to organise some storage for tokens - I'd use linked list.
As simple as this.
EDIT
Ok, if strlen() is the only function allowed, you can first find the length of your source string, then loop through it and replace all non-letter characters with NULL - basically that's what strtok() does.
Then you need to go through your modified source string second time, advancing one token at a time, and find the longest one, using strlen().
This sounds similar to the standard UNIX 'strings' utility.
Keep track of the longest run of printable characters terminated by a NULL.
Walk through the bytes until you hit a printable character. Start counting. If you hit a non-printable character stop counting and throw away the starting point. If you hit a NULL, check to see if the length of the current run is greater then the previous record holder. If so record it, and start looking for the next string.
What defines the "good" substrings compared to the many others -- being lowercase alphas only? (i.e., no spaces, digits, punctuation, uppercase, &c)?
Whatever the predicate P that checks for a character being "good", a single pass over s applying P to each character lets you easily identify the start and end of each "run of good characters", and remember and pick the longest. In pseudocode:
longest_run_length = 0
longest_run_start = longest_run_end = null
status = bad
for i in (all indices over s):
if P(s[i]): # current char is good
if status == bad: # previous one was bad
current_run_start = current_run_end = i
status = good
else: # previous one was also good
current_run_end = i
else: # current char is bad
if status == good: # previous one was good -> end of run
current_run_length = current_run_end - current_run_start + 1
if current_run_length > longest_run_length:
longest_run_start = current_run_start
longest_run_end = current_run_end
longest_run_length = current_run_length
status = bad
# if a good run ends with end-of-string:
if status == good: # previous one was good -> end of run
current_run_length = current_run_end - current_run_start + 1
if current_run_length > longest_run_length:
longest_run_start = current_run_start
longest_run_end = current_run_end
longest_run_length = current_run_length
Why use strlen() at all?
Here's my version which uses no function whatsoever.
#ifdef UNIT_TEST
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#endif
/*
// largest_letter_sequence()
// Returns a pointer to the beginning of the largest letter
// sequence (including trailing characters which are not letters)
// or NULL if no letters are found in s
// Passing NULL in `s` causes undefined behaviour
// If the string has two or more sequences with the same number of letters
// the return value is a pointer to the first sequence.
// The parameter `len`, if not NULL, will have the size of the letter sequence
//
// This function assumes an ASCII-like character set
// ('z' > 'a'; 'z' - 'a' == 25; ('a' <= each of {abc...xyz} <= 'z'))
// and the same for uppercase letters
// Of course, ASCII works for the assumptions :)
*/
const char *largest_letter_sequence(const char *s, size_t *len) {
const char *p = NULL;
const char *pp = NULL;
size_t curlen = 0;
size_t maxlen = 0;
while (*s) {
if ((('a' <= *s) && (*s <= 'z')) || (('A' <= *s) && (*s <= 'Z'))) {
if (p == NULL) p = s;
curlen++;
if (curlen > maxlen) {
maxlen = curlen;
pp = p;
}
} else {
curlen = 0;
p = NULL;
}
s++;
}
if (len != NULL) *len = maxlen;
return pp;
}
#ifdef UNIT_TEST
void fxtest(const char *s) {
char *test;
const char *p;
size_t len;
p = largest_letter_sequence(s, &len);
if (len && (len < 999)) {
test = malloc(len + 1);
if (!test) {
fprintf(stderr, "No memory.\n");
return;
}
strncpy(test, p, len);
test[len] = 0;
printf("%s ==> %s\n", s, test);
free(test);
} else {
if (len == 0) {
printf("no letters found in \"%s\"\n", s);
} else {
fprintf(stderr, "ERROR: string too large\n");
}
}
}
int main(void) {
fxtest("(2034HEY!!11 th[]thisiswhatwewant44");
fxtest("123456789");
fxtest("");
fxtest("aaa%ggg");
return 0;
}
#endif
While I waited for you to post this as a question I coded something up.
This code iterates through a string passed to a "longest" function, and when it finds the first of a sequence of letters it sets a pointer to it and starts counting the length of it. If it is the longest sequence of letters yet seen, it sets another pointer (the 'maxStringStart' pointer) to the beginning of that sequence until it finds a longer one.
At the end, it allocates enough room for the new string and returns a pointer to it.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int isLetter(char c){
return ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') );
}
char *longest(char *s) {
char *newString = 0;
int maxLength = 0;
char *maxStringStart = 0;
int curLength = 0;
char *curStringStart = 0;
do {
//reset the current string length and skip this
//iteration if it's not a letter
if( ! isLetter(*s)) {
curLength = 0;
continue;
}
//increase the current sequence length. If the length before
//incrementing is zero, then it's the first letter of the sequence:
//set the pointer to the beginning of the sequence of letters
if(curLength++ == 0) curStringStart = s;
//if this is the longest sequence so far, set the
//maxStringStart pointer to the beginning of it
//and start increasing the max length.
if(curLength > maxLength) {
maxStringStart = curStringStart;
maxLength++;
}
} while(*s++);
//return null pointer if there were no letters in the string,
//or if we can't allocate any memory.
if(maxLength == 0) return NULL;
if( ! (newString = malloc(maxLength + 1)) ) return NULL;
//copy the longest string into our newly allocated block of
//memory (see my update for the strlen() only requirement)
//and null-terminate the string by putting 0 at the end of it.
memcpy(newString, maxStringStart, maxLength);
newString[maxLength + 1] = 0;
return newString;
}
int main(int argc, char *argv[]) {
int i;
for(i = 1; i < argc; i++) {
printf("longest all-letter string in argument %d:\n", i);
printf(" argument: \"%s\"\n", argv[i]);
printf(" longest: \"%s\"\n\n", longest(argv[i]));
}
return 0;
}
This is my solution in simple C, without any data structures.
I can run it in my terminal like this:
~/c/t $ ./longest "hello there, My name is Carson Myers." "abc123defg4567hijklmnop890"
longest all-letter string in argument 1:
argument: "hello there, My name is Carson Myers."
longest: "Carson"
longest all-letter string in argument 2:
argument: "abc123defg4567hijklmnop890"
longest: "hijklmnop"
~/c/t $
the criteria for what constitutes a letter could be changed in the isLetter() function easily. For example:
return (
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c == '.') ||
(c == ' ') ||
(c == ',') );
would count periods, commas and spaces as 'letters' also.
as per your update:
replace memcpy(newString, maxStringStart, maxLength); with:
int i;
for(i = 0; i < maxLength; i++)
newString[i] = maxStringStart[i];
however, this problem would be much more easily solved with the use of the C standard library:
char *longest(char *s) {
int longest = 0;
int curLength = 0;
char *curString = 0;
char *longestString = 0;
char *tokens = " ,.!?'\"()#$%\r\n;:+-*/\\";
curString = strtok(s, tokens);
do {
curLength = strlen(curString);
if( curLength > longest ) {
longest = curLength;
longestString = curString;
}
} while( curString = strtok(NULL, tokens) );
char *newString = 0;
if( longest == 0 ) return NULL;
if( ! (newString = malloc(longest + 1)) ) return NULL;
strcpy(newString, longestString);
return newString;
}
First, define "string" and define "garbage". What do you consider a valid, non-garbage string? Write down a concrete definition you can program - this is how programming specs get written. Is it a sequence of alphanumeric characters? Should it start with a letter and not a digit?
Once you get that figured out, it's very simple to program. Start with a naive method of looping over the "garbage" looking for what you need. Once you have that, look up useful C library functions (like strtok) to make the code leaner.
Another variant.
#include <stdio.h>
#include <string.h>
int main(void)
{
char s[] = "(2034HEY!!11 th[]thisiswhatwewant44";
int len = strlen(s);
int i = 0;
int biggest = 0;
char* p = s;
while (p[0])
{
if (!((p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z')))
{
p[0] = '\0';
}
p++;
}
for (; i < len; i++)
{
if (s[i] && strlen(&s[i]) > biggest)
{
biggest = strlen(&s[i]);
p = &s[i];
}
}
printf("%s\n", p);
return 0;
}

Resources