Kernighan and Ritchie - exercise 3.3 (expand function) - c

I have solved the exercises 3.3 from the K&R book. The solution I have implemented seems to work, but is a bit verbose and there could be smarter way to write this code. I wanted to ask if there could be problems with the solution I implemented and if there were easier way to write it:
Write a function expand(s1,s2) that expands shorthand notations like
a-z in the string s1 into the equivalent complete list abc...xyz in
s2. Allow for letters of either case and digits, and be prepared to
handle cases like a-b-c and a-z0-9 and -a-z. Arrange that a leading or
trailing - is taken literally
My code is this one:
#include <stdio.h>
void expand(char s1[],char s2[]){
int j=0,i=0;
while(s1[j] != '\0'){
if (s1[j]>= 'a' && s1[j] <= 'z' && s1[j+1] == '-' && s1[j+1]!='\0' && s1[j+2] >= 'a' && s1[j+2] <= 'z' && s1[j+2] !='\0'){
int z = s1[j+2]-s1[j];
int c;
for (c=0;c<=z;c++){
s2[i]= c+s1[j];
i++;
}
j=j+3;
}
else if (s1[j]>= 'A' && s1[j] <= 'Z' && s1[j+1] == '-' && s1[j+1]!='\0' && s1[j+2] >= 'A' && s1[j+2] <= 'Z' && s1[j+2] !='\0'){
int z = s1[j+2]-s1[j];
int c;
for (c=0;c<=z;c++){
s2[i]= c+s1[j];
i++;
}
j=j+3;
}
else if (s1[j]>= '0' && s1[j] <= '9' && s1[j+1] == '-' && s1[j+1]!='\0' && s1[j+2] >= '0' && s1[j+2] <= '9' && s1[j+2] !='\0'){
int z = s1[j+2]-s1[j];
int c;
for (c=0;c<=z;c++){
s2[i]= c+s1[j];
i++;
}
j=j+3;
}
else if (j!= 0 && s1[j] == '-' && (s1[j-1] < s1[j+1])){
int z = s1[j+1]-(1+s1[j-1]);
int c;
for (c=0;c<=z;c++){
s2[i]= c+(s1[j-1]+1);
i++;
}
j=j+2;
}
else if ( s1[j]>= 32 && s1[j] <= 127 && (s1[j+1] != '-' || s1[j+1]>= 32 && s1[j+1] <= 127 )){
s2[i] = s1[j];
j++;
i++;
}
}
s2[i]='\n';
i++;
s2[i]='\0';
}
int main() {
int c;
char s2[100];
expand("-a-c,a-c-g,A-Z0-9--", s2);
printf("%s",s2);
}
The code works in this way:
First it check if there is a triplet of the kind "x-y" where x<y. Then if gives to the array the values from x to y included and jump to the next character after the triplet "x-y". The same is done for upper case letters and for numbers in further if conditions.
the condition else if (j!= 0 && s1[j] == '-' && (s1[j-1] < s1[j+1])) is used to check for cases like "a-c-d1". The code I have implemented in this example will work like this:
Since we start with the 0-th character in "a-c-d" and the pattern "x-y" is present, "abc" will be assigned to the array. then we will directly jump to the second - in "a-c-f". Since this second - is preceded by a letter "c" and followed by a letter "f", and "c"<"f", then the characters between "c" and "f" will be assigned to the array, excluding the initial "c". Then the index for the string will jump of two and reach 1.

Some other way :
you only to know the last char before - and if it is the same type as current one (lower or upper case letter or digit)
when you get a - and previous char is a letter or digit you know you may have to make expansion
if you have a letter or digit after - and it is corresponding to letter/digit before - you know you can expand from char before / to current one.
you do need to look forward but only save previous char and char before -
you do same kind of processing for each different char type (letter/digit)
You can find an example after :
#include <stdio.h>
// handle different char type
typedef enum E_chartype {
LowerCaseLetter,
UpperCaseLetter,
Digit09,
OtherChar
} E_chartype;
// save if we may have a posdible expansion
typedef enum E_states {
NothingStarted,
StartedExpansion
} E_states;
// find type of a char
E_chartype getCharType(char c) {
if ((c >= 'a') && (c <= 'z'))
return LowerCaseLetter;
if (( c >= 'A') && (c <= 'Z'))
return UpperCaseLetter;
if ((c >= '0') && (c <= '9'))
return Digit09;
return OtherChar;
}
void expandopt(char *inS, char *outS) {
// init output string to null string
outS[0] = 0;
char *endS = outS;
E_states automat = NothingStarted;
char savedChar = 0;
int currentIndex;
E_chartype prevCType=OtherChar,savedCType=OtherChar;
char savedC = 0,prevC=0;
// loop on input string
for (currentIndex = 0; inS[currentIndex] != 0;currentIndex++) {
// save current char in variable c for shorter writting
char c = inS[currentIndex];
printf("%c : ",c);
// save type of current char
E_chartype currentCType = getCharType(c);
switch (automat) {
// genersl case notjing yet started
case NothingStarted:
// possibkee expansion if previous chsr is letter or digit and current char is -
if ((prevCType != OtherChar) && (c == '-')) {
printf("start rep\n");
automat = StartedExpansion;
// save the previous char and its type as it eill br the reference fircexpansion
savedCType = prevCType;
savedC = prevC;
} else {
// reset and cooy current char to iutput
automat = NothingStarted;
printf("nothing\n");
*endS++ = c;
}
break;
case StartedExpansion:
// we make ecpansion only if still same char type and letter/digit is strictly after saved one
if ((currentCType == savedCType) && (c > savedC)){
printf("expansion ");
for (char newC
= savedC+1;newC <= c;newC++) {
*endS++ = newC;
}
// save char in case thrre id a - after, which mean nee expansion
savedC = c;
} else {
// save current chsrcsnd its type
savedCType = currentCType;
savedC = c;
// copy previous char (= -) whch was not vopief in case of expansion
*endS++ = prevC;
*endS++ = c;
}
automat = NothingStarted;
break;
}
// save current chsr and type
prevCType = currentCType;
prevC = c;
}
// add 0 at end of string
*endS = 0;
}
int main() {
expandopt("-a-c,a-c-g,A-Z0-9–",s2);
printf("%s\n",s2);
}
Sorry for the code formatting, I did not find good code editor on phone.

Related

String character check

i should realize two very similar functions but i am having problems.
I have to read the string "username", this string can only contain letters (upper and lower case) and spaces.
I have to read the string "key", this string can only contain letters (upper and lower case) and numbers.
If the guidelines are not followed, the user must be able to retrieve the input.
Unfortunately, I cannot use special libraries (only stdio and stdlib).
I realized this:
void checkString(char *i){
int cont;
do {
scanf("%s", i);
if (checkStrLen(6, 6, i) != 0) { //function that controls the size of the string (min,max,string)
for(cont=0; cont<6;){
if((i[cont]>='0' && i[cont]<='9')||
(i[cont]>='A' && i[cont]<='Z')||
(i[cont]>='a' && i[cont]<='z')){
cont++;
}else{
printf("Not valid character");
printf("Try again");
}
}
}else{
printf("\nToo large string");
printf("\nTry again");
}
}while(1);
}
I was thinking of doing something similar.
For the first problem I would replace (i[cont]>='0' && i[cont]<='9') with (i[cont]==' ').
the problem is that I don't understand how to get out of the for if I find a forbidden character during the loop.
I was thinking of using a break, but that would get me out of the whole function.
any advice?
PS how does the function look like? can it be okay or is it completely wrong?
I think the do while loop is not necessary here. do the scanf and get user input first then call checkString. Inside checkString keep your if else statement.
char checkString(char *i){
int cont;
if (checkStrLen(6, 6, i) != 0) { //function that controls the size of the string (min,max,string)
for(cont=0; cont<6;){
if((i[cont]>='0' && i[cont]<='9')||
(i[cont]>='A' && i[cont]<='Z')||
(i[cont]>='a' && i[cont]<='z')){
cont++;
}else{
printf("Not valid character");
printf("Try again");
return i;
}
}
}
else{
printf("\nToo large string");
printf("\nTry again");
}
}
#include <stdio.h>
#define MAXSIZE 100
#define SIZELIM 6
#define true 1
#define false 0
// Returns length of string
// If possible, use strlen() from <string.h> instead
int strlen(char *str) {
char i;
for (i = 0; str[i] != 0 && str[i] != '\n'; i++);
return i;
}
// Returns 1 if strings are equal
// If possible, use strcmp() from <string.h> instead
int streq(const char *x, const char *y) {
char chrx = 1, chry = 1, i;
for (i = 0;
chrx != 0 && chry != 0 && chrx == chry;
chrx = x[i], chry = y[i], i++);
return chrx == chry;
}
// Returns 1 if chr is number or letter
// If possible, use isalnum() from <ctype.h> instead
int isalnum(const char chr) {
return (chr >= '0' && chr <= '9' ||
chr >= 'A' && chr <= 'Z' ||
chr >= 'a' && chr <= 'z');
}
// Checks if string contains numbers and letters only
int isvalid(const char *str) {
int valid = true;
for (int i = 0; str[i] != 0 && str[i] != '\n'; i++) {
if (!isalnum(str[i])) {
valid = false;
break;
}
}
return valid;
}
// Main
int main(void) {
char str[MAXSIZE];
for (;;) {
printf("> ");
fgets(str, MAXSIZE, stdin);
if (streq(str, "quit\n"))
break;
if (strlen(str) > SIZELIM || !isvalid(str)) {
if (strlen(str) > SIZELIM)
puts("String too large");
else if (!isvalid(str))
puts("Not a valid string");
puts("Try again"); }
}
return 0;
}
You can code those functions that you cannot import:
int letters_and_spaces(char c)
{
return c == ' ' || C >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';
}
int letters_and_numbers(char c)
{
return c >= '0' && c <= '9' || C >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';
}
And to use scanf to read spaces you can't use %s. You could change to:
scanf("%100[^\n]*c", i);
BE CAREFUL: I've put 100, supposing i has enough space for that. It will read up to 100 characters (or as many as the number you put there) or until find the \n.

Given a list of words, I am to read them using scanf("%c", &c), create a string out of the letters and print the rest unchanged

For instance, in a sentence such as
Its a great day. Right?
I want to keep reading until I reach a non-letter character, call my helper function on each string created and print the rest unchanged.
This is what I have so far but it only prints the first letter numerous times
void string_create(void) {
char word[1000+1] = {0};
int i = 0;
int j=0;
char c = 0;
while (scanf("%c", &c) == 1) {
if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
word[i] = c;
i++;
}
else {
printf("%s", word);
i=0;
printf("%c", c);
}
}
}
In the end for now, without going into details of the helper function, it should simply print the original sentence unchanged.
Current output:
Its ats great dayat.dayat Right?Right
The problem is here (infinite loop) :
while((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
Use if instead of while.
Try this,
#include <stdio.h>
void string_create(void)
{
char word[1000+1] = {0};
int i = 0;
char c = 0;
scanf("%c",&c);
while ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
{
word[i++]=c;
while((c=getchar()!='\n')&&(c!=EOF)); //to remove white space
scanf("%c",&c);
}
printf("%s",word);
}
int main()
{
string_create();
return 0;
}
Output:
q
w
e
r
t
y
1
qwerty
Process returned 0 (0x0) execution time : 8.205 s
Press any key to continue.
you can also give new line(enter) instead of 1
you can also use this
scanf("%1000[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]",word);
it only read letters

Hello. My program keeps failing to create the string output I expect. Can you notice a flaw?

This function is meant to fill a second string with the filtered results of the first. the filter should remove all special characters and only print lower case permutations of all letters written
I've tried changing the nature of the "ModifyText" loop, and I've done it with pointers+while loop and with for loops both with the condition of ending when the iterator reaches a character \0.
These are the methods I've already tried, both continue to only return the lowercase "the" of the first word in the string, not the entire string with only lowercase alphabet letters
#include <stdio.h>
#include <ctype.h>
#include <string.h>
//
//int ModifyText(char Stringboy[], char output[])
//{
// for(int i=0; Stringboy[i] != '\0'; i++)
// {
// if(Stringboy[i] >= 'A' && Stringboy[i] <= 'Z')
// {
// output[i] = Stringboy[i] + 32;
//
// }
// else if(Stringboy[i] >= 'a' && Stringboy[i] <= 'z')
// {
// output[i] = Stringboy[i];
// }
//}}
int ModifyText(char *Stringboy, char *output)
{
while(*Stringboy != '\0')
{
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
}
else if(*Stringboy >= 'a' && *Stringboy <= 'z')
{
*output = *Stringboy;
}
++Stringboy;
++output;
}
}
int main(void){
char samplearray[] = {"THE quick Brown Fox jumps over the Lazy Dog!***!"};
char dummy[83];
printf("Original Text: \n %s\n", samplearray);
ModifyText(samplearray, dummy);
printf("Modified Text: \n %s\n", dummy);
//letterCounter(dummy); //these two bottom functions have their prints written into them, so they need only be called
//wordCounter(dummy);
printf("length of sample array is %d", strlen(samplearray));
}
This code is only returning a string "the" when it should be returning a string "the quick brown fox jumps over the lazy dog" in the string entitled dummy
When *Stringboy is a space then you do not set *output since neither if condition is true. However, you do increment output. As a result the character after "the" in output will be random data (in your case is is probably NULL) which is why the string ends.
Change the code to this:
while(*Stringboy != '\0')
{
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
}
else
{
*output = *Stringboy;
}
++Stringboy;
++output;
}
*output = '\0';
That way the spaces will be written to the output string.
In your original code, you increment the output pointer also when you didn't copy a letter. You either should write something (e.g. a space) or not increment the output pointer. If you increment the output pointer without writing something, whatever character was there before will stay there. If you're lucky that character is a zero (terminating your string), but it can also be any weird character, including character 7 (a bell sound).
Also, don't forget that your output string needs a terminating zero. Otherwise, weird uninitialized characters might pop up at the end of your string.
int ModifyText(char *Stringboy, char *output)
{
while(*Stringboy != '\0')
{
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
++output;
}
else if(*Stringboy >= 'a' && *Stringboy <= 'z')
{
*output = *Stringboy;
++output;
}
++Stringboy;
}
*output = '\0'; // make sure the output gets a terminating zero
}
Here is a more fancy version, that outputs spaces to replace non-letters. To not get the output flooded with spaces, a boolean variable checks to maximally output one space between the words.
int ModifyText(char *Stringboy, char *output)
{
bool previousWasLetter = false;
while(*Stringboy != '\0')
{
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
++output;
previousWasLetter = true;
}
else if(*Stringboy >= 'a' && *Stringboy <= 'z')
{
*output = *Stringboy;
++output;
previousWasLetter = true;
}
else if (previousWasLetter)
{
*output = ' ';
++output;
previousWasLetter = false;
}
++Stringboy;
}
*output = '\0'; // make sure the output gets a terminating zero
}
You have several mistakes:
You copy characters to a new string only if character is an uppercase letter or if the character is lowercase... but you don't copy anything, when it's not either. As you feed the function with an array allocated in the stack (recently allocated, so probably you got a new page zero filled) the character there could be a \0 char and so, delimited the string. You need to copy the character untouched in case it's not an uppercase character... not only if it is lowercase. This will allow you to copy the spaces (which are neither) for example. Resulting in this code:
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
}
else // if(*Stringboy >= 'a' && *Stringboy <= 'z') // not needed
{
*output = *Stringboy;
}
you dont finalize the output string, putting a \0 character at the end. You should do it past the end of the loop, as the output pointer has been left pointing to the next output char, just add
*output = '\0';
next to the loop.
Some other minor changes (these cannot be considered mistakes, but will silence some warnings got from the compiler on some permitted language inconsistencies you made), like adding a return 0; statement to nonvoid returning functions (this should be a mistake in case you planned to return something from it), change the %d length format for a more portable %zd format string (if you have strlen() returning a long value and int and long are different size, this could lead to problems in some machines), and adding a new line \n character, so the shell prompt gets printed in the next line (and not just after the string length).
So, the code finally should be something like:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
//
//int ModifyText(char Stringboy[], char output[])
//{
// for(int i=0; Stringboy[i] != '\0'; i++)
// {
// if(Stringboy[i] >= 'A' && Stringboy[i] <= 'Z')
// {
// output[i] = Stringboy[i] + 32;
//
// }
// else if(Stringboy[i] >= 'a' && Stringboy[i] <= 'z')
// {
// output[i] = Stringboy[i];
// }
//}}
int ModifyText(char *Stringboy, char *output)
{
while(*Stringboy != '\0')
{
if(*Stringboy >= 'A' && *Stringboy <= 'Z')
{
*output = *Stringboy + 32;
}
else // if(*Stringboy >= 'a' && *Stringboy <= 'z')
{
*output = *Stringboy;
}
++Stringboy;
++output;
}
*output = '\0';
return 0;
}
int main(void){
char samplearray[] = "THE quick Brown Fox jumps over the Lazy Dog!***!"; // braces unneeded.
char dummy[83];
printf("Original Text: \n %s\n", samplearray);
ModifyText(samplearray, dummy);
printf("Modified Text: \n %s\n", dummy);
//letterCounter(dummy); //these two bottom functions have their prints written into them, so they need only be called
//wordCounter(dummy);
printf("length of sample array is %zd\n", strlen(samplearray));
return 0;
}

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]);
}

Change letter with number

I'm doing an exercise, to practice, where the point is to receive a string of numbers and letters, check if it's a letter, transforme it to number with the rule
A = 10, Z = 35
and then place everything in an array. Some operations after.
I know how to do everything except the rule part, no idea about how to check which letter it is and how to replace it with the right number. I know there's a way with something like
if(string[x] == 'a-Z')
but i'm neither sure how that works, or how to pick the right number knowing that it's a letter.
There are many approaches, some more portable than others.
The following looks for thestring[x] in an array. If successful, the pointer difference between it and the start is the value.
const char *alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *p = strchr(alphanum, string[x]);
if (p == NULL || *p == '\0') {
; // Not a digit or A-Z
} else {
int value = p - alphanum;
// do something with the value;
}
I'll leave handling of a-z to the OP. (convert to upper or use another array)
If code assumes ASCII, with its A Z in sequential order:
int ToValue(char ch) {
if (ch >= 'A' && ch <= 'Z') return ch - 'A' + 10;
if (ch >= 'a' && ch <= 'z') return ch - 'a' + 10;
if (ch >= '0' && ch <= '9') return ch - '0';
// No match
return -1;
}
I like to divide functions like that into more functions that deal with smaller pieces of logic.
int isLowerCaseLetter(char c)
{
return ( c >= 'a' && c <= 'z');
}
int isUpperCaseLetter(char c)
{
return ( c >= 'A' && c <= 'Z');
}
int letterToNumber(char c)
{
if ( isdigit(c) )
{
return (c - '0');
}
else if ( isLowerCaseLetter(c) )
{
return (c - 'a' + 10);
}
else if ( isUpperCaseLetter(c) )
{
return (c - 'A' + 10);
}
// Problem
assert(0);
return 0; // Keep the compiler happy
}

Resources