Is there a quick way to retrieve given character's position in the english alphabet in C?
Something like:
int position = get_position('g');
int position = 'g' - 'a' + 1;
In C, char values are convertible to int values and take on their ASCII values. In this case, 'a' is the same as 97 and 'g' is 103. Since the alphabet is contiguous within the ASCII character set, subtracting 'a' from your value gives its relative position. Add 1 if you consider 'a' to be the first (instead of zeroth) position.
You should also probably take into account upper/lower case. In my expereince, counting from 1, is often dangerous because it can lead to off-by-one bugs. As a rule of thumb I always convert to a 1-based index only when interacting with the user, and use 0-based counting internally, to avoid confusion.
int GetPosition(char c)
{
if (c >= 'a' && c <= 'z') {
return c - 'a';
}
else if (c >= 'A' && c <= 'Z') {
return c - 'A';
}
else {
// Indicate that it isn't a letter.
return -1;
}
}
This will work with EBCDIC and is case-insensitive:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int getpos (char c)
{
int pos;
const char * alphabet = "abcdefghijklmnopqrstuvwxyz";
const char * found;
c = tolower ((unsigned char)c);
found = strchr (alphabet, c);
pos = found - alphabet;
if (!found)
pos = 0;
else if (pos == 26)
pos = 0;
else
pos++;
return pos;
}
int main ()
{
char tests[] = {'A', '%', 'a', 'z', 'M', 0};
char * c;
for (c = tests; *c; c++) {
printf ("%d\n", *c - 'a' + 1);
printf ("%d\n", getpos (*c));
}
return 0;
}
See http://codepad.org/5u5uO5ZR if you want to run it.
Take the input of the alphabet:
scanf("%c",ch);
Just subtract 96 from the ascii value of the character. This can be done within the printf argument:
printf("%d",ch-96);
Related
I am fairly new to programming and I am trying to convert a string containing a base 10 number to an integer value following this pseudo algorithm in c.
start with n = 0
read a character from the string and call it c
if the value of c is between '0' and '9' (48 and 57):
n = n * 10 +(c-'0')
read the next character from the string and repeat
else return n
here is the rough basics of what i wrote down however I am not clear on how to read a character from the string. i guess im asking if i understand the pseudocode correctly.
stoi(char *string){
int n = 0;
int i;
char c;
for (i = 0;i < n ; i++){
if (c[i] <= '9' && c[i] >= '0'){
n = n *10 +(c - '0')}
else{
return n
}
}
}
You were close, you just need to traverse the string to get the value of each digit.
Basically you have two ways to do it.
Using array notation:
int stoi(const char *str)
{
int n = 0;
for (int i = 0; str[i] != '\0'; i++)
{
char c = str[i];
if ((c >= '0') && (c <= '9'))
{
n = n * 10 + (c - '0');
}
else
{
break;
}
}
return n;
}
or using pointer arithmetic:
int stoi(const char *str)
{
int n = 0;
while (*str != '\0')
{
char c = *str;
if ((c >= '0') && (c <= '9'))
{
n = n * 10 + (c - '0');
}
else
{
break;
}
str++;
}
return n;
}
Note that in both cases we iterate until the null character '\0' (which is the one that marks the end of the string) is found.
Also, prefer const char *string over char *string when the function doesn't need to modify the string (like in this case).
Congrats on starting your C journey!
One of the most important aspects of strings in C is that, technically, there are none. A string is not a primitive type like in Java. You CAN'T do:
String myString = "Hello";
In C, each string is just an array of multiple characters. That means the word Hello is just the array of [H,e,l,l,o,\0]. Here, the \0 indicates the end of the word. This means you can easily access any character in a string by using indexes (like in a normal array):
char *myString = "Hello";
printf("%c", myString[0]); //Here %c indicates to print a character
This will then print H, since H is the first character in the string. I hope you can see how you can access the any character in the string.
I need to build a function that gets an input and capitalizes only the first letter, doesn't print numbers, capitalizes after a . for a new sentence, and capitalizes all words between a double quotation marks ".
This is what I got until now:
#include <stdio.h>
#define MAX 100
int main()
{
char str[MAX] = { 0 };
int i;
//input string
printf("Enter a string: ");
scanf("%[^\n]s", str); //read string with spaces
//capitalize first character of words
for (i = 0; str[i] != '\0'; i++)
{
//check first character is lowercase alphabet
if (i == 0)
{
if ((str[i] >= 'a' && str[i] <= 'z'))
str[i] = str[i] - 32; //subtract 32 to make it capital
continue; //continue to the loop
}
if (str[i] == '.')//check dot
{
//if dot is found, check next character
++i;
//check next character is lowercase alphabet
if (str[i] >= 'a' && str[i] <= 'z')
{
str[i] = str[i] - 32; //subtract 32 to make it capital
continue; //continue to the loop
}
}
else
{
//all other uppercase characters should be in lowercase
if (str[i] >= 'A' && str[i] <= 'Z')
str[i] = str[i] + 32; //subtract 32 to make it small/lowercase
}
}
printf("Capitalize string is: %s\n", str);
return 0;
}
I cant find a way to remove all numbers from input and convert all lowercase to uppercase inside a " plus code for not printing numbers if user input them.
if I input
I am young. You are young. All of us are young.
"I think we need some help. Please" HELP. NO, NO NO,
I DO NOT
NEED HELP
WHATSOEVER.
"Today’s date is
15/2/2021"...
I am 18 years old, are you 20 years old? Maybe 30 years?
output:
I am young. You are young. All of us are young.
"I THINK WE NEED SOME HELP. PLEASE" help. No, no no,
i do not
need help
whatsoever.
"TODAY’S DATE IS
//"...
I am years old, are you years old? maybe years?
The C standard library provides a set of functions, in ctype.h, that will help you
Of particular interest, would be:
isdigit() - returns true if digit
isalpha() - returns true if alphabet character
isalnum() - returns true if alpha/numeric character
islower() - returns true if lower case character
isupper() - returns true if upper case character
tolower() - converts character to lower case
toupper() - converts character to upper case
So, for example, you could replace the test/modify with:
if ( islower( str[i] ) )
{
str[i] = toupper( str[i] );
}
Pedantically, islower() and toupper() return an unsigned int but that's a separate matter...
You can remove letters from a string if you keep two indices, one for reading and one for writing. The following loop will remove all digits from a string:
int j = 0; // writing index, j <= i
int i; // reading index
for (i = 0; str[i]; i++) {
int c = (unsigned char) str[i];
if (!isdigit(c)) str[j++] = c;
}
str[j] = '\0';
(I've used to character classification functions from <ctype.h> mentioned in Andrew' answer.)
This is safe, because j will always be smaller or equal to i. Don't forget to mark the end of the filtered string with the nullterminator, '\0'. You can combine this filtering with your already existing code for replacing characters.
In your code, you capitalize letters only if they are directly behind a full stop. That's usually not the case, there's a space between full stop and the next word. It's better to establish a context:
shift: capitalize the next letter (beginning or after full stop.)
lock: capitalize all letters (inside quotation marks.)
When you read a letter, decide whether to capitalize it or not depending of these two states.
Putting the filtering and the "shift context§ together:
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char str[] = "one. two. THREE. 4, 5, 6. \"seven\", eight!";
int shift = 1; // Capitalize next letter
int lock = 0; // Capitalize all letters
int j = 0; // writing index, j <= i
int i; // reading index
for (i = 0; str[i]; i++) {
int c = (unsigned char) str[i];
if (isdigit(c)) continue;
if (isalpha(c)) {
if (shift || lock) {
str[j++] = toupper(c);
shift = 0;
} else {
str[j++] = tolower(c);
}
} else {
if (c == '"') lock = !lock;
if (c == '.') shift = 1;
str[j++] = c;
}
}
str[j] = '\0';
puts(str);
printf("(length: %d)\n", j);
return 0;
}
In order to remove some characters, you should use 2 index variables: one for reading and one for writing back to the same array.
If you are allowed to use <ctype.h>, it is a much more portable and efficient way to test character types.
Also do not use scanf() with protection against buffer overflow. It is as bad as using gets(). Given the difficulty in specifying the maximum number of bytes to store into str, you should use fgets() instead of scanf().
Here is a modified version:
#include <ctype.h>
#include <stdio.h>
#define MAX 100
int main() {
char str[MAX];
int i, j;
unsigned char last, inquote;
//input string
printf("Enter a string: ");
if (!fgets(str, sizeof str, stdin)) { //read string with spaces
// empty file
return 1;
}
last = '.'; // force conversion of first character
inquote = 0;
//capitalize first character of words
for (i = j = 0; str[i] != '\0'; i++) {
unsigned char c = str[i];
//discard digits
if (isdigit(c)) {
continue;
}
//handle double quotes:
if (c == '"') {
inquote ^= 1;
}
//upper case letters after . and inside double quotes
if (last == '.' || inquote) {
str[j++] = toupper(c);
} else {
str[j++] = tolower(c);
}
if (!isspace(c) && c != '"') {
// ignore spaces and quotes for the dot rule
last = c;
}
}
str[j] = '\0'; // set the null terminator in case characters were removed
printf("Capitalized string is: %s", str);
return 0;
}
I am doing the exercise in the C Programming language book, and exercise 2-3 asked us to write a function htoi to convert a hexadecimal number to decimal number.
This is the code I wrote, however when it runs, it always show that my hexadecimal number is illegal.
Please help!
#include<stdio.h>
#define TRUE 1
#define FALSE 0
int htoi (char s[]);
int main() {
printf("The decimal number is %d\n", htoi("0x134"));
return 0;
}
int htoi (char s[]) {
int j; /* counter for the string */
int temp; /* temp number in between conversion */
int number; /* the converted number */
int ishex; /* if the number is a valid hexadecimal number */
char c;
number = 0;
temp = 0;
ishex = FALSE;
if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
ishex = TRUE;
}
else {
ishex = FALSE;
printf("This is not valid hexadecimal number.\n");
return number = 0;
}
if (ishex == TRUE) {
for (j = 2; (c = s[j]) != EOF; ++j) {
if (c >= '0' && c <= '9')
temp = c - '0';
else if (c >= 'a' && c <= 'f')
temp = 10 + c - 'a';
else if (c >= 'A' && c <= 'F')
temp = 10 + c - 'A';
else {
printf("This is a illegal hexadecimal number.\n");
ishex = FALSE;
return 0;
}
number = number * 16 + temp;
}
}
return number;
}
A string is a sequence of characters that terminates at the first '\0' character. That means "0x134" terminates with a '\0' character value, not an EOF value.
You are operating on a sequence of characters that you expect to be terminated by an EOF value, but that is simply not possible. I'll explain why later... Suffice to say for now, the string "0x134" contains no EOF value.
Your loop reaches the string-terminating '\0', which isn't in the range 0..9, a..f or A..F and so this branch executes:
else {
printf("This is a illegal hexadecimal number.\n");
ishex = FALSE;
return 0;
}
Perhaps you meant to write your loop like so:
for (j = 2; (c = s[j]) != '\0'; ++j) {
/* SNIP */
}
I promised to explain what is wrong with expecting EOF to exist as a character value. Assuming an unsigned char is 8 bits, getchar can return one of 256 character values, and it will return them as a positive unsigned char value... OR it can return the negative int value EOF, corresponding to an error or end-of-file.
Confused? In an empty file, there are no characters... Yet if you try to read a character from the file, you will get EOF every time, in spite of there being no characters. Hence, EOF is not a character value. It's an int value, and should be treated as such before you attempt to convert the value to a character, like so:
int c = getchar();
if (c == EOF) {
/* Here, c is NOT A CHARACTER VALUE! *
* It's more like an error code ... *
* XXX: Break or return or something */
}
else {
/* Here, c IS a character value, ... *
* so the following conversion is ok */
char ch = c;
}
On another note, c >= '0' && c <= '9' will evaluate truthfully when c is one of the digits in the range 0..9... This is a requirement from the C standard
Neither c >= 'a' && c <= 'f' nor c >= 'A' && c <= 'F' are required to evaluate truthfully under any circumstance, however. It happens to work on your system, because you are using ASCII which contains all of the lowercase letters in one contiguous block, and all of the uppercase letters in another contiguous block. C does not require that ASCII be the character set.
If you want this code to work portably, you might consider something like:
char alpha_digit[] = "aAbBcCdDeEfF";
if (c >= '0' && c <= '9') {
c -= '0';
}
else if (strchr(alpha_digit, c)) {
c = 10 + (strchr(alpha_digit, c) - alpha_digit) / 2;
}
else {
/* SNIP... XXX invalid digit */
}
Suppose if I pass a string like "I am Programmer".
If a letter has occurred one time it should print "I has occurred 1 time", or else if a letter appears twice in the string it should print "a has occurred 2 times", "m has occurred 3 times" and so on for every letter in the string. I searched it and found in some website. Is there any way we could rewrite the code because I didn't understand the code.
#include <stdio.h>
#include <string.h>
int main()
{
char string[100];
int c = 0, count[26] = {0};
printf("Enter a string\n");
gets(string);
while (string[c] != '\0')
{
/** Considering characters from 'a' to 'z' only
and ignoring others */
if (string[c] >= 'a' && string[c] <= 'z')
count[string[c]-'a']++;
c++;
}
for (c = 0; c < 26; c++)
{
/** Printing only those characters
whose count is at least 1 */
if (count[c] != 0)
printf("%c occurs %d times in the entered string.\n",c+'a',count[c]);
}
return 0;
}
Ok here is the rewrite, the original code is better but this one might be easier to understand:
#include <stdio.h>
#include <string.h>
int main()
{
char cur_char;
char string[100];
int index = 0, count[255] = {0};
printf("Enter a string\n");
gets(string);
while (string[index] != '\0')
{
char cur_char = string[index];
// cur_char is a char but it acts as the index of the array like
// if it was an unsigned short
count[cur_char] = count[cur_char] + 1;
index++;
}
for (index = 0; index < 255; index++)
{
if (count[index] != 0)
printf("%c occurs %d times in the entered string.\n", index, count[index]);
}
return 0;
}
A variable type char can be considered as an integer (it's how they are stored in the memory anyway) so you can write:
int test = 'a';
printf("%i", test);
And it will print you 97. Also letters from a to z are represented by continuous intergers, that means 'b' = 98. So taht also means 'b' - 'a' = 1
In your solution, they create an array of 26 integers to count the occurence of each letters betwin 'a' and 'z' (note that they ignore all others including A-Z by doing this)
They decided that in the array count, index 0 is here to count occurences of a, 1 for b .... 25 for z, that explains this:
count[string[c]-'a']++;
If string[c] is a b then string[c]-'a' = 1 so we have our index for count array and increase the amount of occurence of b.
So all you need to understand this code is that you can manipulate a char like an int basically, you should make a quick search about what is ASCII code as well.
If you still need a rewrite of this code to understand, tell me.
Using only stdio.h, string.h and stdlib.h libraries how would I go about implementing this?
I'm quite new to programming so please bear with me!
Allocate a new char array of the same length as your string. Convince yourself that this is enough space. Don't forget the NUL.
Loop through the string, copying to the new string only those characters that are alphanumeric. You can't do this portably without also including <ctype.h> and using a function/macro from that header, unless you're going to enumerate all characters that you consider alphanumeric.
Again, don't forget the NUL.
Since this is homework, here is the verbal description:
Run a loop over the original string and use the functions isalnum() to determine if a character is alphanumeric. Maintain a second char array of reasonable size and every time you encounter an AlphaNum, insert it to that array. Once all AlphaNum characters have been copied to the second array, NULL terminate it and you have your string.
Note: isalnum() is defined in ctype.h, so if you aren't allowed to use that, you may have to define this function for yourself. That is another exercise of it's own.
Every char you read in your string is a byte (you can think it as a number between 0 and 255, and that's how the computers handle them) so you just need to check the ascii table to see what letter refers to.
Every alphanumerical char is in this range: [48, 58] (for numbers), or [65, 90] (upper case), or [97, 122] (lower case).
Look at this:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 64
int isalphanum(char); /*states if a char is alphanumerical or not*/
char *getalphanum(char *, char*); /*modifies the second string to get the result*/
int main(void) {
char in[SIZE] = "Hello, W##########orl...,.,d!"; /*just a random to try out*/
char out[SIZE];
getalphanum(in, out);
printf("%s", out);
return 0;
}
int isalphanum(char a) {
if ((a >= 48) && (a <= 58))
return 1;
if ((a >= 65) && (a <= 90))
return 1;
if ((a >= 97) && (a <= 122))
return 1;
return 0;
}
char *getalphanum(char *s, char *t) {
if ((s == NULL) || (t == NULL)) /*tests if the strings are "handble"*/
return NULL;
int i = 0;
int j = 0;
char c;
while ((c = *(s + i)) != '\0') {
if (isalphanum(c)){
*(t + j) = c;
j++;
}
i++;
}
*(t + j) = '\0';
return t;
}
This code works and is very simple and can be improved, but there is evertything you need.
The best way is to use the isalnum() from ctype.h but now that is not an option, I have written a not-standard/non-portable function called isalnum_not_prefered() which is the equivalent of ctype.h's isalnum().
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int isalnum_not_prefered(char s)
{
if((s >= 'A' && s <= 'Z') ||
(s >= 'a' && s <= 'z') ||
(s >= '0' && s <= '9'))
return 1;
return 0;
}
int main(void)
{
char str[] = "this!234$#&##$^is5##$a##$4677~=_?}valid2234kjstring";
int len = strlen(str);
int i, j=0;
char *newstr1 = NULL;
char *newstr2 = NULL;
if ((newstr1 = (char *) malloc(sizeof(char) * len + 1)) == NULL) {
printf("unable to allocate memory \n");
return -1;
}
for (i=0 ; i<len ; i++) {
if (isalnum(str[i])) {
newstr1[j] = str[i];
j++;
}
}
newstr1[j] = '\0';
if ((newstr2 = (char *) malloc(sizeof(char) * len + 1)) == NULL) {
printf("unable to allocate memory \n");
return -1;
}
j=0;
for (i=0 ; i<len ; i++) {
if (isalnum_not_prefered(str[i])) {
newstr2[j] = str[i];
j++;
}
}
newstr2[j] = '\0';
printf("string : %s \n", str);
printf("result1 : %s \n", newstr1);
printf("result2 : %s \n", newstr2);
free(newstr1);
free(newstr2);
return 0;
}
Points to note:
strings in C is terminated with \0. So the new string that your are populating should also terminate with \0
malloc()'ed memory must be free()'ed
malloc() errors should be handled
this code is not portable as it assumes the machines character set to be ASCII. If the hardware supports some other character set (say EBCDIC) then this may not work as expected.
Hope this helps!