The code should accept a character and it should check whether its between 'j' and 'p'.
If it is between 'j' and 'p' it should print yes or else it should print no.
I have tried to do something about it but the only ideas I got is this:
if (a=='j' || a=='k' || a=='k' || a=='l' || a=='m' || a=='n' || a=='o' || a=='p')
{
printf("YES");
}
else
{
printf("NO");
}
You can avoid all the alternative tests by using a function like strchr():
if (strchr("jklmnop", a)) {
puts("YES");
} else {
puts("NO");
}
The obvious approach is to do something like
if (a >= 'j' && a <= 'p') {
// ...
}
but that has a problem if you want to write portable code.
The C standard only requires that the characters '0' through '9' appear consecutively and in order. If you're following the standard to a t, you shouldn't assume that 'j' through 'p' appear together and can be used with a pair of >= and <= tests. If you add additional qualifications like requiring an ASCII compatible character set, it's a different story.
It depends on what you mean by "between j and p".
If you mean "Only lowercase English letters between j and p", then one portable way of writing it down is
if (strchr("jklmnop", a)) ...
If you mean "Character codes between that of 'j' and that of 'p', in whatever encoding is used by the machine", then one portable way of writing it down is
if (a >= 'j' && a <= 'p') ...
If your encoding is ASCII, then the two notions above strictly coincide for any range of English letters.
If your encoding is EBCDIC, then they coincide for the range j..p, but not say for the range i..p.
It is guaranteed that all English letters between j and p are included in the range of the codes in any standards-compliant encoding, but there might be additional, non-English-letter characters in the same range.
Finally, for completeness, if by "between j and p" you mean "letters of the user's language, whatever it is, that are between j and p", then one correct way of writing it down is probably
setlocale (LC_ALL, ""); // first statement of the program
...
if (strcoll(a, "j") >= 0 && strcoll(a, "p") <= 0) ...
Note that here, a is not a character as above, but a string. It is up to you to ensure that it contains a single character of the user's language (which is not the same thing as a single char element). Ensuring this is very non-trivial.
TL;DR
if (a >= 'j' && a <= 'p') will probably work for whatever task you currently have, but don't assume it will always work.
try this code
#include <stdio.h>
int main()
{
char a;
printf("enter the letter :");
scanf("%c",&a);
if(a>='j' && a<='p')
printf("yes the letter is between j and p");
else
printf("No the given letter is not between j and p");
}
Each and every alphabet has an ASCII code which is an integer so you can perform it like this,
char a;
scanf("%c",&a);
if(a>='j'&&a<='p')
{
printf("YES");
}
else
{
printf("NO");
}
Assuming lowercase letters form a contiguous block in the execution set, which is true for ASCII, you can write:
if (a >= 'j' && a <= 'p') ...
Assuming a is an int containing a char value, You can write this as a single test, but a good compiler should be able to generate the same code for the more readable test above:
if ((unsigned)(a - 'j') <= (unsigned)('p' - 'j')) ...
You could also test if a is in a set of characters, which will work regardless of the target encoding:
if (a != 0 && strchr("jklmnop", a)) ...
The test for a != 0 can be removed if you know a cannot be a null byte.
Character literals (This is a character literal: 'a') are just numbers. Almost all computers use a ASCII-compatible encoding (there are very few exceptions).
ASCII assumed, for example 'a' is a 97 for your computer, 'j' a 106. if you write a=='j' you basically write a==106. Using character literals is just syntax sugar, it makes it a lot easier for humans to read but the computer does not care.
This means, you have to check if a is between 106 and 112. You probably know a better way to do that than you current way. But instead of 106 and 112 write 'j' and 'p', because it easier to read.
Related
I want to extract season and episode from a filename in C. For example, if the input string is "Game.of.Thrones.S05E02.720p.HDTV.x264-IMMERSE.mkv", then I want to extract the substring "S05E02" out of it.
At the moment, I'm using a very naive approach for matching characters one at a time. Concretely, I am finding 'S' and then checking if the next two characters are both numbers between '0' and '9' and then the subsequent character is 'E' and the next two characters to 'E' are also between '0' and '9'.
// Return index if pattern found. Return -1 otherwise
int get_tvshow_details(const char filename[])
{
unsigned short filename_len = strlen(filename);
for (int i = 0; i < filename_len-5; ++i) {
char season_prefix = filename[i];
char episode_prefix = filename [i+3];
char season_left_digit = filename[i+1];
char season_right_digit = filename[i+2];
char episode_left_digit = filename[i+4];
char episode_right_digit = filename[i+5];
if ((season_prefix == 'S' || season_prefix == 's')
&& (episode_prefix == 'E' || episode_prefix == 'e')
&& (season_left_digit >= '0' && season_left_digit <= '9')
&& (season_right_digit >= '0' && season_right_digit <= '9')
&& (episode_left_digit >= '0' && episode_left_digit <= '9')
&& (episode_right_digit >= '0' && episode_right_digit <= '9')) {
printf("match found at %d\n", i);
return i;
}
}
return -1;
}
Is there a more efficient way in C to extract the following pattern: S<2_digit_number>E<2_digit_number> from any tv show filename?
I'd like to propose another solution, very similar to regex, but not dependent on a separate library for regex. C's format strings are quite powerful, though primitive. I think they could actually work in this case.
The format string we'll need is- %*[^.].%*[^.].%*[^.].%*1[Ss]%d%*1[Ee]%d.
Let's compare this to a string like Game.of.Thrones.S05E02.720p.HDTV.x264-IMMERSE.mkv
The first %*[^.]. will consume Game. but not capture it.
The second %*[^.]. will consume of. but not capture it.
The second %*[^.]. will consume Thrones. but not capture it.
Now the fun part, %*1[Ss]%d%*1[Ee]%d. is designed to capture S05E02., and also extract the 05 and 02 into integer variables. Let's discuss this.
%*1[Ss] will consume only 1 letter that is either S or s but not capture it
%d will consume the digits afterwards (05 in this case) and store it into an integer
%*1[Ee] will consume only 1 letter that is either E or e but not capture it
Finally, %d. will consume the digits afterwards, store it inside an integer and capture the . right after.
If used properly, it should look like-
// Just a dummy string literal for testing
char s[] = "Game.of.Thrones.S05E02.720p.HDTV.x264-IMMERSE.mkv";
// Variables to store the numbers in
int seas, ep;
printf("%d\n", sscanf(s, "%*[^.].%*[^.].%*[^.].%*1[Ss]%d%*1[Ee]%d.", &seas, &ep));
You may notice, we're also printing the return value of sscanf (you don't have to print it, you can just store it). This is very important. If sscanf returns 2 (that is, the number of captured variables), you know that it was a successful match and the provided string is indeed valid. If it returns anything else, it indicates either non-complete match or a complete failure (in case of negative values).
If you run this piece of code, you get-
2
Which is correct. If you print seas and ep later, you get-
5 2
I'm writing code that need to limit the use to enter characters that be only from A to H. Greater then H should not be accepted.
I saw that with numbers I can use that like:
if (input == 0 - 9) return 1;
But, how I do that A to H (char)?
The C Standard does not specify that character encoding should be ASCII, though it is likely. Nonetheless, it is possible for the encoding to be other (EBCDIC, for example), and the characters of the Latin alphabet may not be encoded in a contiguous sequence. This would cause problems for solutions that compare char values directly.
One solution is to create a string that holds valid input characters, and to use strchr() to search for the input in this string in order to validate:
#include <stdio.h>
#include <string.h>
int main(void)
{
char *valid_input = "ABCDEFGH";
char input;
printf("Enter a letter from 'A' - 'H': ");
if (scanf("%c", &input) == 1) {
if (input == '\0' || strchr(valid_input, input) == NULL) {
printf("Input '%c' is invalid\n", input);
} else {
puts("Valid input");
}
}
return 0;
}
This approach is portable, though solutions which compare ASCII values are likely to work in practice. Note that in the original code that I posted, an edge case was missed, as pointed out by #chux. It is possible to enter a '\0' character from the keyboard (or to obtain one by other methods), and since a string contains the '\0' character, this would be accepted as valid input. I have updated the validation code to check for this condition.
Yet there is another advantage to using the above solution. Consider the following comparison-style code:
if (input >= 'A' || input <= 'H') {
puts("Valid input");
} else {
puts("Invalid input");
}
Now, suppose that conditions for valid input change, and the program must be modified. It is simpler to modify a validation string, for example to change to:
char *valid_input = "ABCDEFGHIJ";
With the comparison code, which may occur in more than one location, each comparison must be found in the code. But with the validation string, only one line of code needs to be found and modified.
Further, the validation string is simpler for more complex requirements. For example, if valid input is a character in the range 'A' - 'I' or a character in the range '0' - '9', the validation string can simply be changed to:
char *valid_input = "ABCDEFGHI0123456789";
The comparison method begins to look unwieldy:
if ((input >= 'A' && input <= 'I') || (input >= '0' && input <= '9')) {
puts("Valid input");
} else {
puts("Invalid input");
}
Do note that one of the few requirements placed on character encoding by the C Standard is that the characters '0', ..., '9' be encoded in a contiguous sequence. This does allow for portable direct comparison of decimal digit characters, and also for reliably finding the integer value associated with a decimal digit character through subtraction:
char ch = '3';
int num;
if (ch >= '0' && ch <= '9') {
printf("'%c' is a decimal digit\n", ch);
num = ch - '0';
printf("'%c' represents integer value %d\n", ch, num);
}
The if statement you present here is equal to:
if (input == -9) return 1;
which will return 1 in the case of an input equal to -9, so there is no range checking at all.
To allow numbers from 0 to 9 you have to compare like:
if (input >= 0 && input <= 9) /* range valid */
or with the characters that you want (A to H)1:
if (input >= 'A' && input <= 'H') /* range valid */
If you want to return 1 if the input is not in a valid range just put the logical not operator (!) in front of the condition:
if (!(input >= 'A' && input <= 'H')) return 1; /* range invalid */
1 You should take care of the used range if working with conditions that uses character ranges because the range needs an encoding that specify the letters in an incrementing order without any gaps in between the range (ASCII code e.g.: A = 65, B = 66, C = 67, ..., Z = 90).
There are encoding where this rule breaks. As the other answer of #DavidBowling stated there is for example EBCDIC (e.g.: A = 193, B = 194, ..., I = 200, J = 209, ..., Z = 233) which has some gaps in between the range from A to Z. Nevertheless the condition: (input >= 'A' && input <= 'H') will work with both encodings.
I never fall about such an implementation yet and it is very unlikely. Most implementations uses the ASCII code for which the condition works.
Nevertheless his answer provides a solution that is working in every case.
It's as simple as:
if(input >='A' && input<='H') return 1;
C doesn't let you specify ranges like 0 - 9.
In fact that's an arithmetic expression "zero minus nine" and evaluates to minus nine (of course).
Nerd Corner:
As others point out this is not guaranteed by the C standard because it doesn't specify a character encoding though in practice all modern platforms encode these characters the same as ASCII. So it's very unlikely you will come unstuck and if you're working in an environment where it won't work you'd have been told!
A truly portable implementation could be:
#include <string.h>//contains strchr()
const char* alpha="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const char* pos=strchr(alpha,input);
if(pos!=NULL&&(pos-alpha)<8) return 1;
This tries to find the character in an alphabet string then determines if the character (if any) pointed to is before 'I'.
This is total over engineering and not the answer you're looking for.
I'm writing a program that reads lines from a file
I need to print out the numbers, the lines read are stored in a character array:
char line[255];
//code to read line from file here
for (c=0;c<256;c++)
{
if (line[c]<58 && line[c]>47)
printf("the character is: %c\n",line[c]);
}
the configuration file has the following lines:
buttons 3
the result I'd like to get is the character is 3, instead I get 3,9,4,4
Hope I've provided sufficient information.
thanks
Your if-statement is wrong.
You can express it much clearer, and more correctly as:
if ('0' <= line[c] && line[c] <= '9')
{
printf("the character is: %c\n",line[c]);
}
Your loop runs for 256 characters, even though the input of "buttons" only has 7 characters. You're running off into memory that is not yours, and likely finding 9, 4, 4, there by random chance.
You want:
for (int c=0; c < 256; ++c)
{
if (line[c] == '\0') // If the end of the input is found, stop the loop.
{
break;
}
if ('0' <= line[c] && line[c] <= '9')
{
printf("the character is: %c\n",line[c]);
}
}
An extension of abelenky's post:
abelenky presents 2 (out of many) solutions to the problem. An important aspect of writing code is readability. abelenky's first solution maximizes readability.
if (line[c] >= '0' && line[c] <= '9')
{
printf("the character is: %c\n",line[c]);
}
Everyone is aware that ASCII characters are mapped to integer values, but not everyone can readily recall the range of values associated with each types of character (numbers, letters, capital letters, etc.).
This is why C supports the single quotes: ' '
It is reasonable to assume that ASCII values for integers increment as do integers from 0-9, thus using '0' and '9' in your conditional statement improves readability. Adopting a more legible style of code will improve your and the life of anyone who views your code.
Happy coding!
I have homework to do and I need some help. I didn't come here to get someone to do my work, just to help me.
I have to create my own string.h "library" (actually header and function file), so I am forbidden to use #include <string.h> and #include <ctypes.h>. They also recommended us not to use malloc, but it was just a recommendation, not forbidden.
For most of the functions I know how to write them.
I planned to save "strings" like arrays of chars like:
char array[50];
But I came to a problem of creating toupper and tolower functions.
Sure, I can make huge switch cases or a lot if (else if's) like this:
if(string[i]=='a') {string[i]=='A' };
else if(string[i]=='b') {string[i]=='B' };
.
.
.
else if(string[i]=='z') {string[i]=='Z' };
But is there any better solution?
Strings are going to be created randomly so they will look somewhat like this:
ThisISSomESTRing123.
So after toupper function, randomly generated string should look like this:
THISISSOMESTRING123.
Also how would you create puts function (printing) so everything would be in same row? Just "printf" inside "for" loop?
Your system probably uses ASCII. In ASCII, the codepoints of lowercase characters and uppercase characters are sequential.
So we can just do:
void to_upper(char *message) {
while (*message) {
if (*message >= 'a' && *message <= 'z')
*message = *message - 'a' + 'A';
message++;
}
}
Other character encodings can become much more complicated. For example, EBCDIC doesn't have contiguous characters. And UTF-8 introduces a world of problems because of the numerous languages that you need to support.
You can just check if the character is within the range of characters, say between 'a' and 'z' and just add or subtract 32, which is the difference between the ascii value of capital and lower letters. See the ascii table here: http://www.asciitable.com/
Just do
if (string[i] >= 'a' && string[i] <= 'z') {
string[i] = string[i] - 'a' + 'A';
}
It will convert lower case to upper case by changing a..z to 0..26 then adding the ASCII value for 'A' to it.
There's a neat trick for converting ASCII cases. Consider these characters:
A - binary 01000001
a - binary 01100001
As we can see, the difference is in the 6th bit, counting from the right. Indeed, the difference between uppercase and lowercase ASCII chars is 2^5 = 32. So, to convert a letter to uppercase, simply AND it with 0xDF (11011111) to set that bit to 0. In this way you don't even have to check if the character is in uppercase already.
Note that this will break non-letter characters that are above 0x60, namely the backtick, {, |, } and ~. But as long as you don't have these in your strings, it should be fine to use this and you can avoid an if :).
Note: Only use that as a cool trick for this homework. Normally you should just use proper, tested solutions (aka string.h).
void toUpper(char *arr) {
while (*arr) {
if (*arr >= 'a' && *arr <= 'z')
*arr = *arr - 'a' + 'A';
arr++;
}
}
use this function to make all the letters uppercase in a string just call the toUpper funcn and give your array as a prarameter.
for printing the array just use for loop and move in array index elements and print the letters.
for(int i=0;arr[i] !='\0';i++)
{
printf("%c",arr[i]);
}
this will print every elements in the array which is the string,
I am currently writing a little sort function. I can only use stdio libary, so I wrote my 'own strcmp' function.
int ownstrcmp(char a[], char b[])
{
int i = 0;
while( a[i] == b[i] )
{
if( a[i] == '\0' )
return 0;
++i;
}
return ( a[i] < b[i]) ? 1 : -1;
}
This works great for me. But there is one little problem: What can I do for 'non-Standard-Chars'? Like "ä,ü,ß Their decimal ASCII value is greater than the normal chars, so it sort the string 'example' behind 'ääää'.
I have already read about locale, but the only library that i can use is stdio.h. Is there a 'simple' solution for this problem?
Your question is somewhat vague. First of all, how characters with umlaut are represented depends on your encoding. For example, my computer's locale is set to Greek, meaning that in place of those special Latin characters I have Greek characters. You can't assume anything like that, as far as I can tell.
Second, the answer to your question depends on your representation. Are you still using a "one char per character" representation? If that's so, the above code might still work.
If you're using multi char representation, for example two chars per character, you should change your code so that it exits when two consecutive chars are \0.
Generally, you may want to look into how wchar_t and its family of functions (specifically wcscmp) are implemented.
For german the umlauts ä,ö,ü and ß will be sorted as if they occur in their 'expanded' form:
ä -> ae
ö -> oe
ü -> ue
ß -> ss
In order to get the collation according to the standard you could expand the strings before comparing.
You need to know the encoding the characters are in, and make sure you treat the strings properly. If the encoding is multi-byte, you must start reading (and comparing) individual characters, not bytes.
Also, the way to compare characters internationally varies with the locale, there's no single solution. In some languages, 'ä' sorts after 'z', in some it sorts right next to 'a'.
One simple way of implementing this is of course to create a table which holds the relative order for each character, like so:
unsigned char character_order[256];
character_order[(unsigned char) 'a'] = 1;
character_order[(unsigned char) 'ä'] = character_order[(unsigned char) 'a'];
/* ... and so on ... */
Then instead of subtracting the character's encoded value (which no longer can be used as a "proxy" for the sorting order of the character), you compare the character_order values.
The above assumes single-byte encoding, i.e. Latin-1 or something, since the array size is only 256.
Also note casts to unsigned char when indexing with character literals.
If you are using ISO/IEC_8859-16 encoding, which is the normal enconding for German Language, it's enough to transform your char to unsigned char.
In this way chars can be represented in interval 0-255, suitable for this standard.
Under UTF8 this can help, following your code
if ((a[i] > 0) ^ (b[i] > 0))
return a[i] > 0 ? 1 : -1;
else
return a[i] < b[i] ? 1 : -1;
But you have to check cases like ownstrcmp("ab", "abc");
Furthermore your code doesn't work like strcmp() in <string.h>
A value greater than zero indicates that the first character that does not match has a greater value in str1 than in str2; And a value less than zero indicates the opposite.
I would do it like this:
int ownstrcmp(char a[], char b[])
{
int i = 0;
while(a[i] == b[i]) {
if (a[i] == 0) return 0;
++i;
}
if ((a[i] == 0) || (b[i] == 0))
return a[i] != 0 ? 1 : -1;
if ((a[i] > 0) ^ (b[i] > 0))
return a[i] < 0 ? 1 : -1;
else
return a[i] > b[i] ? 1 : -1;
}