I'm trying to compare two chars to see if one is greater than the other. To see if they were equal, I used strcmp. Is there anything similar to strcmp that I can use?
A char variable is actually an 8-bit integral value. It will have values from 0 to 255. These are almost always ASCII codes, but other encodings are allowed. 0 stands for the C-null character, and 255 stands for an empty symbol.
So, when you write the following assignment:
char a = 'a';
It is the same thing as this on an ASCII system.
char a = 97;
So, you can compare two char variables using the >, <, ==, <=, >= operators:
char a = 'a';
char b = 'b';
if( a < b ) printf("%c is smaller than %c", a, b);
if( a > b ) printf("%c is smaller than %c", a, b);
if( a == b ) printf("%c is equal to %c", a, b);
Note that even if ASCII is not required, this function will work because C requires that the digits are in consecutive order:
int isdigit(char c) {
if(c >= '0' && c <= '9')
return 1;
return 0;
}
In C the char type has a numeric value so the > operator will work just fine for example
#include <stdio.h>
main() {
char a='z';
char b='h';
if ( a > b ) {
printf("%c greater than %c\n",a,b);
}
}
I believe you are trying to compare two strings representing values, the function you are looking for is:
int atoi(const char *nptr);
or
long int strtol(const char *nptr, char **endptr, int base);
these functions will allow you to convert a string to an int/long int:
int val = strtol("555", NULL, 10);
and compare it to another value.
int main (int argc, char *argv[])
{
long int val = 0;
if (argc < 2)
{
fprintf(stderr, "Usage: %s number\n", argv[0]);
exit(EXIT_FAILURE);
}
val = strtol(argv[1], NULL, 10);
printf("%d is %s than 555\n", val, val > 555 ? "bigger" : "smaller");
return 0;
}
You are going to have to roll your own way of comparing characters. The C standard only mandates that the digits 0 to 9 have an easy way to compare them using basic c1 > c2 style comparison. This is NOT guaranteed to work for other characters like letters. (Although in practice it often will for simple ASCII ranges like a-z and A-Z.)
One way to do it, often unsatisfactory, is to convert the characters to strings and use strcoll().
Related
I'm trying to make sure that the array entered at the command line is only letters, Capital and lowercase.
If it is numbers or anything else then I want to end the program.
Now, I know I can do this with tons of if statements to see:
if it is between this and that
else this and that
else this and that.
But I would like to try and learn a more efficient way to do this because I'm sure there is one with a for loop I just havent figured it out. I ask because I want the user to enter a key that is x amount long. And to achieve the desired / required string length I used a similar method of multiple if else statements.
#include <stdio.h>
#include <string.h>
int validate_key(int argc, string argv[]);
int main(int argc, string argv[])
{
string input;
int score;
score = validate_key(argc, argv);
if (score == 0)
{
// if required key is valid, next function of program here
}
}
int validate_key(int argc, string argv[])
{
//KEY VALIDATION
int l = 0; //initialize length variable
string s;
//To make sure that the string entered at command line is the required 26 characters,
//and that it isnt empty
if (argc == 2) //make sure there are no spaces in the entered string
{
s = argv[1]; //assign key to string s
l = strlen(s); //check length of KEY
}
//check to see string isnt NULL / empty
if (argc !=0 && l == 26)
{
//make a for loop that scans the array making sure it is between two values?
//attempting to check argv to make sure it is a lowercase and or uppercase string
for (int i = 0; i < l; i++)
{
int charValue = argv[1][i];
if ( ( charValue > 64 && charValue < 91 ) || ( charValue > 96 && charValue < 123 ) )
{
printf("%c\n", charValue); //to show me that it made it into the if statement
}
else
return 1;
}
return 0;
}
else if (l <= 25 && l >= 1) //entered key is too small
{
printf("Please Enter 26 Letter Key \n");
printf("value of l: %d\n", l);
return 1;
}
else //entered key is empty
{
//printf("value of l: %d\n", l);
printf("missing command-line argument\n");
return 1;
}
}
Use isalpha():
7.4.1.2 The isalpha function
Synopsis
#include <ctype.h>
int isalpha(int c);
Description
The isalpha function tests for any character for which isupper or
islower is true, or any character that is one of a locale-specific set
of alphabetic characters for which none of iscntrl, isdigit, ispunct,
or isspace is true.200) In the "C" locale, isalpha returns true only
for the characters for which isupper or islower is true.
In your code:
for (int i = 0; i < l; i++)
{
// see notes below regarding the cast
int charValue = ( unsigned char ) argv[1][i];
if ( isalpha( charValue ) )
{
printf("%c\n", charValue); //to show me that it made it into the if statement
}
else
return 1;
}
Note, though, that the value passed must be representable as an unsigned char:
The header <ctype.h> declares several functions useful for classifying and mapping characters. In all cases the argument is an int, the value of which shall be representable as an unsigned char or shall equal the value of the macro EOF. If the argument has any other value, the behavior is undefined.
The basic operation will always be to iterate over the characters in the input string and check whether they are that what you want them to be: uppercase or lowercase letters. There are some functions that make it more convenient for you to code.
To avoid coding the ASCII number ranges yourself, you can use the C standard function isalpha() to check a single character whether it is a letter.
You could also use the strcspn function to find the number of matching characters at the start of your string. Your matching set can be a string with all the ASCII letters. If the returned length is the length of the whole string, there were no other characters in it. If the returned length is less than the length of the string, then there is a non-letter character... This is probably less efficient for the computer because strcspn does not simply check whether the characters are in a range, but whether the characters appear in the matching string.
The particular question was in regard of testing for non-alphabetic characters.
There are already two quality answers referring you to isalpha().
The meta- question is "how can I write less code?"
The following (using isalpha()) is offered as a teaching example that performs the same function as the OP code above. By compacting the code to fewer lines, a reader is able to scan its operation without scrolling. Unused variables such as input and s are quick to find and expunge.
#include <stdio.h>
#include <string.h>
#include <cs50.h> // Missing from OP code
// defining the function ahead of its use. Definition is its own prototype.
int unique26( string arg ) {
int i = 0;
// test all alpha and is exactly 26 chars long
while( isalpha( (unsigned char) arg[i] ) i++;
if( i != 26 || arg[i] )
return 0; // bad
// test no duplications in the sample
for( i = 0; arg[i]; i++ )
for( int j = i + 1; arg[j]; j++ )
if( arg[j] == arg[i] )
return 0; // bad
return 1; // good
}
int main( int argc, string argv[] )
{
if( argc != 2 || !unique26( argv[1] ) )
{
printf( "Usage: %s <key (26 unique alphabetic chars> \n", argv[0] );
return 1;
}
// more code here
return 0;
}
I'd be happy to answer any questions this example code.
EDIT:
To write even less code, the function unique26() could use strchr(), a tested and proven function from what is called "the C string library".
int unique26( string arg ) {
int i = 0;
while( isalpha( (unsigned char) arg[i] ) i++;
if( i != 26 || arg[i] )
return 0; // bad
// test no duplications in the sample
for( i = 1; arg[i] && strchr( &arg[i], arg[i-1] ) == NULL; i++ ) {}
return arg[i] == '\0;
}
It's good to be aware of library functions, even if you may not have use for some... until you do.
first post (as you would know) and the form tells me that my title is bad and will get downvoted but I can't do better :) I've worked on this a bunch already.
I'm trying to cipher text by adding a number given in the command line to a string.
Why does
include <stdio.h>
int main(int argc, char * argv[])
{
printf("%i", argc);
char k = argv[1][0];
printf("%c", k);
char * s = "a";
printf("%c", s[0] + 0);
}
correctly print "a" (besides for printing argc and k)
but when the last line is
printf("%c", s[0] + k);
it just prints argc and k and then nothing. I wanted it to print 20a (when running ./question 0).
( I tried
char k = 0;
char * s = "a";
printf("%c", s[0] + k);
and that does work :( )
It seems like the fact that k is coming from argv is the issue but I don't have any idea why (not that I really understand any of this)
Thanks!
argv and argc and "a" are all red herrings. They have nothing to do with the problem. The problem lies in not understanding the difference between two character values, '0' and 0 (the latter is aso known as '\0').
In order to understand the difference I suggest experimenting with this program:
#include <stdio.h>
int main(void) {
char a = 'a', b = '0';
printf ("as char: a=%c b=%c sum=%c\n", a, b, a+b);
printf ("as int: a=%d b=%d sum=%d\n", a, b, a+b);
}
Use different values for b, including 0, 1, '0' and '1' and see what happens.
The answer is very simple.
The ASCII code of 'a' is 97.
Assuming only the printable characters in the arguments, the lowest printable ASCII code from the argv is 32.
97+32 = integer overflow which is UB - on ideone.com system it is -127
you can try yourself
https://ideone.com/D8DLcy
#include <stdio.h>
int main(void) {
for(char x = 32; x < 127; x++)
{
char m = 'a' + x;
printf("'a' + %c = char value in decimal is:%hhd - and the char is%c\n", x, m, m);
}
return 0;
}
The problem is that the expression s[0] + k is that adding a letter and a number together (conceptually speaking, ignoring the data types for a minute) can easily result in a value that is past the end of the alphabet, and printing it out as if it was a letter isn't necessarily going to work.
Bonus problem: reading the command line parameter into a single character isn't giving you a value of 0, but '0' which has a numerical value of 48. You can't just pull out the first character from the string. What if the user runs the program and passes 10 as a parameter?
You need to make sure that the result of your calculation is within the bounds of the alphabet.
As suggested by commenters above, take a look at the ASCII table, and try using some character constants sich as 'a' 'z' 'A' and 'Z' to modify the result
From the information you provided, it looks like you're implementing a simple shift cipher. Note the use of modulo for cases where the input for k is greater than 25.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING 16
int main(int argc, char *argv[])
{
char num[MAX_STRING];
char * s = "a";
int k;
if (argc == 2)
{
snprintf(num,MAX_STRING, argv[1], 10);
k = (int)strtol(num, NULL, 10) % 26;
printf("%c\n", s[0] + k);
}
else
{
fprintf(stderr,"Invalid number of arguments\n");
return(EXIT_FAILURE);
}
return(EXIT_SUCCESS);
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have to write a program that converts an user input (which is a string) to an Integer. In the same time it should check, if the user input really is a number.
And also everything in one method.
and NO LIBRARY FUNCTIONS allowed.
I can't figure any idea how to do it. All I got for the beginning is just this pathetic structure
#include <stdio.h>
void main()
{
char input[100];
int i;
int sum = 0;
printf("Type a String which will be converted to an Integer: ");
scanf("%c, &input");
for (i = 0; i < 100; i++)
{
}
}
I appreciate any help, thanks
The conversion is the easy part...
But if you must not use library functions,
there is only one way to take a string, and that is argv;
there is only one way to give an integer, and that is the exit code of the program.
So, without much ado:
int main( int argc, char * argv[] )
{
int rc = 0;
if ( argc == 2 ) // one, and only one parameter given
{
unsigned i = 0;
// C guarantees that '0'-'9' have consecutive values
while ( argv[1][i] >= '0' && argv[1][i] <= '9' )
{
rc *= 10;
rc += argv[1][i] - '0';
++i;
}
}
return rc;
}
I did not implement checking for '+' or '-', and did not come up with a way to signal "input is not a number". I also just stop parsing at the first non-digit. All this could probably be improved upon, but this should give you an idea of how to work around the "no library functions" restriction.
(Since this sounds like a homework, you should have to write some code of your own. I already gave you three big spoons of helping regarding argv, the '0'-'9', and the conversion itself.)
Call as:
<program name> <value>
(E.g. ./myprogram 28)
Check return code with (for Linux shell):
echo $?
On Windows it's something about echo %ERRORLEVEL% or somesuch... perhaps a helpful Windows user will drop a comment about this.
Source for the "'0'-'9' consecutive" claim: ISO/IEC 9899:1999 5.2.1 Character sets, paragraph 3:
In both the source and execution basic character sets, the value of each character after 0 in the above list of decimal digits shall be one greater than the value of the previous.
I'm sure this is preserved in C11, but I only have the older C99 paper available.
Take hightes digit and add it to number, multiply the number by 10 and add the next digit. And so on:
#include <stdio.h> // scanf, printf
void main()
{
char input[100];
printf("Type a String which will be converted to an Integer: ");
scanf("%s", input);
int number = 0;
int neg = input[0] == '-';
int i = neg ? 1 : 0;
while ( input[i] >= '0' && input[i] <= '9' )
{
number *= 10; // multiply number by 10
number += input[i] - '0'; // convet ASCII '0'..'9' to digit 0..9 and add it to number
i ++; // step one digit forward
}
if ( neg )
number *= -1;
printf( "string %s -> number %d", input, number );
}
input[i] - '0' works, because ASCII characters '0'..'9' have ascending ASCII codes from 48 to 57.
So basically you want to know how something like the standard library atoi works. In order to do this, you need to consider how strings represent numbers.
Basically, a string (that represents a number) is a list o digits from 0 to 9. The string abcd (where a, b, c, d are placeholders for any digit) represents the number a*10 ^ 3 + b*10^2 + c * 10 + d (considering base 10 here, similar for other bases). So basically you need to decompose the string as shown above and perform the required arhitmetic operations:
// s - the string to convert
int result = 0;
for (int index = 0; index < strlen(s); index++) {
result = result * 10 + s[index] - '0';
}
The operation s[index] - '0' converts the character that represent a digit to its value.
// the function returns true for success , and false for failure
// the result is stored in result parameter
// nb: overflow not handled
int charToInt(char *buff,int *result){
*result=0;
char c;
while(c=*buff++){
if((c < '0') || (c >'9')) // accept only digits;
return 0;
*result *= 10;
*result += c-'0';
}
return 1;
}
Lot of things which are missed. Firstly taking a string in is done by scanf("%s",input); By the way in which you are receiving it, it only stores a character, secondly run the loop till the length of the string recieved. Check the below code.
#include <stdio.h>
#include<string.h>
void main()
{
char input[100];
int i;
int sum = 0;
printf("Type a String which will be converted to an Integer: ");
scanf("%s", input);
for (i = 0; i < strlen(input); i++)
{
if(input[i]>=48 && input[i]<=57)
{
//do something, it is a digit
printf("%d",input[i]-48);
//48 is ascii value of 0
}
}
Try it:
#include <stdio.h>
void main()
{
char input[100];
int i,j;
int val = 0;
printf("Type a String which will be converted to an Integer: ");
scanf("%s",input);
for(j=0; input[j] != '\0'; j++); // find string size
for (i = 0; i < j; i++)
{
val = val * 10 + input[i] - 48;
}
}
If you want your code to be portable to systems that don't use ASCII, you'll have to loop over your char array and compare each individual character in the source against each possible number character, like so:
int digit;
switch(arr[i]) {
case '0':
digit=0; break;
case '1':
digit=1; break;
// etc
default:
// error handling
}
Then, add the digit to your result variable (after multiplying it by 10).
If you can assume ASCII, you can replace the whole switch statement by this:
if(isdigit(arr[i])) {
digit=arr[i] - '0';
} else {
// error handling
}
This works because in the ASCII table, all digits are found in a single range, in ascending order. By subtracting the ordinal value of the zero character, you get the value of that digit. By adding the isdigit() macro, you additionally ensure that only digit characters are converted in this manner.
I've been trying to fix this source code for a long time but the compiler still shows error.
#include<cs50.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
int main(int argc, char* argv[])
{
char ptext[40];
int i=0;
if(argc!=2)
{
printf("invalid key");
return 1;
}
else
printf("enter plain text\n");
ptext= GetString();
int key= atoi(argv[1]);
int n=strlen(ptext);
while( ptext[i]!= '\0')
{
if( ptext[i]>65 && ptext[i]<90)
{
int c= (ptext+key)%26;
int d= c+26;
printf("%c", d);
}
else if( ptext[i]>97 && ptext[i]<122)
{
int c= (ptext+key)%26;
int d= c+26;
printf("%c", d);
}
else
{
printf("%c",ptext[i]);
}
i++;
}
}
The errors it shows while compiling are array type 'char [40]' is not assignable (which does nothing even when a number smaller than 40 is entered or the brackets are left empty), and invalid operands to binary operation int c = (ptext+key)%26.
Couple of things:
What you really need ptext to be is a char*, not an array. I'm guessing GetString() will return a string, or a char[]/char* what have you. Depending on how GetString() works, you might need to test for a NULL return.
At the line int c= (ptext+key)%26; it appears you're trying to process ptext[i]. Perhaps you forgot to include the indexer?
And just a suggestion, if using ASCII, at lines like if( ptext[i]>65 && ptext[i]<90) you can use the char values themselves instead of numbers so you don't have to pore over the ASCII tables. You can do it like so: if(ptext[i] >= 'A' && ptext[i] <= 'Z').
Notice above, also, I changed the comparators > and < to >= and <=. Are not 'A' and 'Z' valid characters?
When using the modulo as you are, for a Caesar Cipher, you want the index of the character in the alphabet. So in the case it's a capital letter, you want to subtract 'A' (or as you so aptly know, 65 in ASCII) like so : `int c= (ptext[i] - 'A' + key) % 26;'.
Change char ptext[40]; to char *ptext;
The GetString() function from cs50.h dynamically allocates some memory and returns a pointer to it. In C it is not possible to assign to an array, nor to return an array.
When you have finished accessing the string's contents, do free(ptext); to release the memory used.
I'm trying to compare two chars to see if one is greater than the other. To see if they were equal, I used strcmp. Is there anything similar to strcmp that I can use?
A char variable is actually an 8-bit integral value. It will have values from 0 to 255. These are almost always ASCII codes, but other encodings are allowed. 0 stands for the C-null character, and 255 stands for an empty symbol.
So, when you write the following assignment:
char a = 'a';
It is the same thing as this on an ASCII system.
char a = 97;
So, you can compare two char variables using the >, <, ==, <=, >= operators:
char a = 'a';
char b = 'b';
if( a < b ) printf("%c is smaller than %c", a, b);
if( a > b ) printf("%c is smaller than %c", a, b);
if( a == b ) printf("%c is equal to %c", a, b);
Note that even if ASCII is not required, this function will work because C requires that the digits are in consecutive order:
int isdigit(char c) {
if(c >= '0' && c <= '9')
return 1;
return 0;
}
In C the char type has a numeric value so the > operator will work just fine for example
#include <stdio.h>
main() {
char a='z';
char b='h';
if ( a > b ) {
printf("%c greater than %c\n",a,b);
}
}
I believe you are trying to compare two strings representing values, the function you are looking for is:
int atoi(const char *nptr);
or
long int strtol(const char *nptr, char **endptr, int base);
these functions will allow you to convert a string to an int/long int:
int val = strtol("555", NULL, 10);
and compare it to another value.
int main (int argc, char *argv[])
{
long int val = 0;
if (argc < 2)
{
fprintf(stderr, "Usage: %s number\n", argv[0]);
exit(EXIT_FAILURE);
}
val = strtol(argv[1], NULL, 10);
printf("%d is %s than 555\n", val, val > 555 ? "bigger" : "smaller");
return 0;
}
You are going to have to roll your own way of comparing characters. The C standard only mandates that the digits 0 to 9 have an easy way to compare them using basic c1 > c2 style comparison. This is NOT guaranteed to work for other characters like letters. (Although in practice it often will for simple ASCII ranges like a-z and A-Z.)
One way to do it, often unsatisfactory, is to convert the characters to strings and use strcoll().