Cesar Cipher out of bounds in Array - c

Guys i found this caesar cipher code in some site.... But when i run it its showing segmentation fault in online compilers..but in c compiler tat i'm using its showing processor fault... can anyone pls point out the wrong in this code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define caesar(x) rot(13, x)
#define decaesar(x) rot(13, x)
#define decrypt_rot(x, y) rot((26-x), y)
void rot(int c, char *str)
{
int l = strlen(str);
const char *alpha[2] = { "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"};
int i;
for (i = 0; i < l; i++)
{
if (!isalpha(str[i]))
continue;
str[i] = alpha[isupper(str[i])][((int)(tolower(str[i])-'a')+c)%26];
}
}
int main()
{
char str[] = "This is a top secret text message!";
printf("Original: %s\n", str);
caesar(str);
printf("Encrypted: %s\n", str);
decaesar(str);
printf("Decrypted: %s\n", str);
return 0;
}

Your code is correct except for one detail, which might be confusing for a newbie.
It is ok to assume that the function isupper() returns a boolean value 1 or 0, but if you check the documentation it says A value different from zero (i.e., true) if indeed c is an uppercase alphabetic letter. Zero (i.e., false) otherwise.
This and the fact that isupper() is returning an int and not a _Bool is causing the problem.
int isupper ( int c );
When returning true isupper() might return any non_zero value. In my case it returns 8 ( a specific bit-field ). Probably the same in yours.
All you have to do is cast the return of isupper() to _Bool
printf("%d %d" ,(_Bool)isupper('A') , ((int)(tolower(str[i])-'a')+c)%26 ) ;

The problem is most likely your use of isupper as index. It's not guaranteed to return 1 for true values, just that it will return "true" (which may be any non-zero value).
You can solve this by using the ternary expression:
alpha[isupper(str[i]) ? 1 : 0][...]

In the first iteration of your loop, you are trying to write to alpha[256][6], (isupper does not always return 0 or 1)
isupper returns: A value different from zero (i.e., true) if indeed c is an
uppercase alphabetic letter. Zero (i.e., false) otherwise.
alpha[isupper(str[i]) != 0][...] will do the trick
Also note that you should always cast the argument you pass to
isupper(), isalnum(), etc. to unsigned char

Related

How to use isdigit function in C

I'm a complete beginner doing the cs50 course and I need to check if an argument from a user is a digit or not.
this is the code:
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
int main(void)
{
int i = 1;
if (isdigit(i) == 1)
{
printf("i is a digit");
}
else if (isdigit(i) == 0)
{
printf("i is not a digit");
}
return 0;
}
When I run this code I basically get a reverse of what I should be getting. When i is a number it prints out "i is not a number" and visa versa.
What am I doing wrong? I thought isdigit returns a non-zero value if it is a digit and 0 if not. Basically 1 being true and 0 being false. Is this not correct?
Much appreciated, Thanks!
What am I doing wrong?
"The isdigit function tests for any decimal-digit character". i with a value of 1 is not a digit character.
Try i = '1';. Then i will have the value of a digit character.
Code is testing the return value incorrectly. #tadman. is...() returns 0 or non-zero.
// if (isdigit(i) == 1)
if (isdigit(i))
Note: is...(int ch) functions are only valid for ch in the unsigned char range and EOF.
If you read the documentation for isdigit() you'll note the return value is expressed as:
Non-zero value if the character is a numeric character, zero otherwise.
In other words, don't compare to exactly one, that's not assured. Compare to non-zero.
That being said, this works on characters not integers, although in C the line is blurred. What you want is to ensure this is part of a string, like:
char* n = "12345";
if (isdigit(n[0]) == 0) {
...
}
In your case you're asking if ASCII character 1 is a digit, which it is not. That's the "Start of Heading" (SOH) control character.
isdigit is a character classification function.
It will return zero or non-zero depending on if a character (or rather, a character promoted to an int) is a digit.
For example:
int i = '1'; // Initialize to the character '1'
if (isdigit(i))
{
printf("i is a digit");
}
else
{
printf("i is not a digit");
}
Note that isdigit returns a non-zero value for digit characters, it doesn't have to be 1.
The argument to isdigit should be a single character, not a number. Thus your test code should more properly be
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char c = '1';
if(isdigit(c))
printf("c is a digit");
else
printf("c is not a digit");
return 0;
}
Your code should stick to the definition of the function, and not make assumptions about the returned value if it is a digit - the actual returned value may be implementation dependent, here's a better C-style, though as others have have said, you should be passing in a char, not an int - did the compiler not complain about that?
if (isdigit(i)) {
printf("i is a digit");
} else {
printf("i is not a digit");
}

Count the amount of individual characters (vowels) within a string in C

I've just started programming in C, and I have to create a program that counts how many vowels a string has. So far I have this:
int a;
int len = strlen(text)-1
for(a=0;a==len;++a){
if(text[a]=='a'){
++vocals;}
I'm clueless on what's wrong, because it will always print 0. I understand my code as:
starting on the first char until the last one before \0,
compare them to 'a', and if they do equal, add one to the counter.
What's wrong with my code?
Check your tutorials or textbook on the syntax and semantics of the for loop.
It requires a continuation condition, i.e. "loop as long as this is true".
So in your code you should change to:
for(a=0; a<len; ++a)
change this
for(a=0;a==len;++a)
to
for(a=0;a<=len;++a)
first iteration a is not equal to len so it will never enter the loop. you want to iterate over this for loop as long as a is lesser of eual to len, second statement does precisely that.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char* text = "this is a test";
int i, vocals;
int len = strlen(text);
for(i=0;i<len;++i){
if(text[i]=='a'||text[i]=='e'||text[i]=='i'||text[i]=='o'||text[i]=='u')
++vocals;
}
printf("%d\n", vocals);
}
This is a working little program.
Let's look at the main together:
First we declare a char arrays, since you omitted that part i assume your string is correctly formed.
The for loop continues till i becames equal to len. It's a good programming practice to use < or > instead of != or == to increment the strength of the code. Anyway since it's a small program you can even use != which means "Execute the for loop till i becames equal to len"
In the if statement we are just checking if the current character is equal to 'a' or 'e' or 'i' or 'o' or 'u'. As you may now guess || operator means or.
EDIT:
There are a lot of more efficient (and complex) way to do this. For example using Regular Expression. If you're interested there are a lot of good tutorial online, for example this
This code snippet
int a;
int len = strlen(text)-1
for(a=0;a==len;++a){
if(text[a]=='a'){
++vocals;}
does not make great sense.
For example the character 'a' is not the only vowel, the condition a == len is evaluated to true only when the string contains just one character.
You can write a separate function that counts vowels in a string.
Here is a demonstrative program.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
size_t count_vowels( const char *s )
{
const char *vowels = "aeiou";
size_t count = 0;
for ( ; *s; ++s )
{
if ( strchr( vowels, tolower( ( unsigned char )*s ) ) )
{
++count;
}
}
return count;
}
int main(void)
{
char s[] = "Hello Pelput";
printf( "There are %zu vowels in the string\n\"%s\"\n",
count_vowels( s ), s );
return 0;
}
The program output is
There are 4 vowels in the string
"Hello Pelput"

How to check an edge case in taking command line argument in C and evaluating to int or double?

So I have an assignment to figure out whether a number on the command line is either an integer or a double.
I have it mostly figured it out by doing:
sscanf(argv[x], "%lf", &d)
Where "d" is a double. I then cast it to an int and then subtract "d" with itself to check to see if it is 0.0 as such.
d - (int)d == 0.0
My problem is if the command line arguments contains doubles that can be technically classified as ints.
I need to classify 3.0 as a double whereas my solution considers it an int.
For example initializing the program.
a.out 3.0
I need it to print out
"3.0 is a double"
However right now it becomes
"3 is an int."
What would be a way to check for this? I did look around for similar problems which led me to the current solution but just this one edge case I do not know how to account for.
Thank you.
For example, a way like this:
#include <stdio.h>
int main(int argc, char *argv[]){
if(argc != 2){
puts("Need an argument!");
return -1;
}
int int_v, read_len = 0;
double double_v;
printf("'%s' is ", argv[1]);
//==1 : It was able to read normally.
//!argv[1][read_len] : It used all the argument strings.
if(sscanf(argv[1], "%d%n", &int_v, &read_len) == 1 && !argv[1][read_len])
puts("an int.");
else if(sscanf(argv[1], "%lf%n", &double_v, &read_len) == 1 && !argv[1][read_len])
puts("a double.");
else
puts("isn't the expected input.");
}
To test if a string will covert to a int and/or double (completely, without integer overflow, without undefined behavior), call strtol()/strtod(). #Tom Karzes
The trouble with a sscanf() approach is that the result is undefined behavior (UB) on overflow. To properly detect, use strtol()/strtod().
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
bool is_int(const char *src) {
char *endptr;
// Clear, so it may be tested after strtol().
errno = 0;
// Using 0 here allows 0x1234, octal 0123 and decimal 1234.
// or use 10 to allow only decimal text.
long num = strtol(src, &endptr, 0 /* or 10 */);
#if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
if (num < INT_MIN || num > INT_MAX) {
errno = ERANGE;
}
#endif
return !errno && endptr > src && *endptr == '\0';
}
bool is_double(const char *src) {
char *endptr;
// Clear, so it may be tested after strtod().
strtod(src, &endptr);
// In this case, detecting over/underflow IMO is not a concern.
return endptr > src && *endptr == '\0';
}
It is not entirely clear what the specific expectations are for your program, but it has at least something to do with the form of the input, since "3.0" must be classified as a double. If the form is all it should care about, then you should not try to convert the argument strings to numbers at all, for then you will run into trouble with unrepresentable values. In that case, you should analyze the character sequence of the argument to see whether it matches the pattern of an integer, and if not, whether it matches the pattern of a floating-point number.
For example:
int main(int argc, char *argv[]) {
for (int arg_num = 1; arg_num < argc; arg_num++) {
char *arg = argv[arg_num];
int i = (arg[0] == '-' || arg[0] == '+') ? 1 : 0; // skip any leading sign
// scan through all the decimal digits
while(isdigit(arg[i])) {
++i;
}
printf("Argument %d is %s.\n", arg_num, arg[i] ? "floating-point" : "integer");
}
}
That makes several assumptions, chief among them:
the question is strictly about form, so that the properties of your system's built-in data types (such as int and double) are not relevant.
each argument will have the form of either an integer or a floating-point number, so that eliminating "integer" as a possibility leaves "floating-point" as the only alternative. If "neither" is a possibility that must also be accommodated, then you'll also need to compare the inputs that do not have integer form to a pattern for floating-point numbers, too.
only decimal (or smaller radix) integers need be accommodated -- not, for example, hexadecimal inputs.
Under those assumptions, particularly the first, it is not just unnecessary but counterproductive to attempt to convert the arguments to one of the built-in numeric data types, because you would then come to the wrong conclusion about arguments that, say, are not within the bounds of representable values for those types.
For example, consider how the program should classify "9000000000". It has the form of an integer, but supposing that your system's int type has 31 value bits, that type cannot accommodate a value as large as the one the string represents.
int main (int argc,char *argv[])
{
if(argc==2)
{
int i;
double d;
d=atof(argv[1]);
i=atoi(argv[1]);
if(d!=i)
printf("%s is a double.",argv[1]);
else if(d==i)
printf("%s is an int.",argv[1]);
}
else
printf("Invalid input\n");
return 0;
}
You must add #include <stdlib.h>

Why is strlen causing a segmentation fault in C?

(Warning) Yes this is a part of an assignment I am working on, but I am completely desperate at this point and NO I am not looking for you guys to solve it for me, but any hint would be much appreciated!(/Warning)
I am pretty much trying to make an interactive menu, the user is meant to input an expression (For example "5 3 +") and the program should detect that it's in postfix notation, unfortunately I have been getting segmentation fault errors and I suspect they have something to do with the use of the strlen function.
EDIT: I was able to make it work, first the char expression[25] = {NULL}; line
becomes char expression[25] = {'\0'};
And when calling the determine_notation function I removed the [25] from the array I am passing like so:
determine_notation(expression, expr_length);
Also the input[length] part I changed to input[length-2] since like mentioned in a previous comment, input[length] == '\0' and input[length--] == '\n'.
All in all thanks for all the help!
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int determine_notation(char input[25], int length);
int main(void)
{
char expression[25] = {NULL}; // Initializing character array to NULL
int notation;
int expr_length;
printf("Please enter your expression to detect and convert it's notation: ");
fgets( expression, 25, stdin );
expr_length = strlen(expression[25]); // Determining size of array input until the NULL terminator
notation = determine_notation( expression[25], expr_length );
printf("%d\n", notation);
}
int determine_notation(char input[25], int length) // Determines notation
{
if(isdigit(input[0]) == 0)
{
printf("This is a prefix expression\n");
return 0;
}
else if(isdigit(input[length]) == 0)
{
printf("This is a postfix expression\n");
return 1;
}
else
{
printf("This is an infix expression\n");
return 2;
}
}
You probably got a warning explaining that you are converting a char to a pointer in this call:
expr_length = strlen(expression[25]);
// ^^^^
This is the problem - your code is referencing a non-existent element past the end of the array (an undefined behavior) and tries to pass it to strlen.
Since strlen takes a pointer to the beginning of the string, the call needs to be
expr_length = strlen(expression); // Determining size of array input until the NULL terminator

Why these c code not working? Whats wrong with these?

#include < stdio.h >
#include < string.h >
int main()
{
unsigned char a;
FILE *P;
P=fopen("mola.txt","r");
while((a=getc(P))!=EOF)
printf("%c",a);
}
Whats wrong with these code? When I compile it gives warning "comparison is always true due to limited range of data type." What does that warning mean?
You are storing the result of getc in a char. It should be an int. There's also a C FAQ on it. Also you should check the return value of the fopen.
P=fopen("mola.txt","r");
if (NULL == P) {
perror("fopen"):
}
Also the while looks fishy. Try indenting ?
while((a=getc(P)) != EOF)
printf("%c",a);
It means just what it says
comparison is always true due to limited range of data type.
The range of the data type in question (the a, which is unsigned char) is from 0 to 255 (really UCHAR_MAX);
The EOF value is -1
You are comparing a (from 0 to 255) with -1
(a != -1)
the condition will always be true
Try:
#include <stdio.h>
#include <string.h>
int main()
{
int a;
FILE *P;
P=fopen("tryit2.c","r");
while(EOF != (a = fgetc(P))) {
printf("%c",a);
}
}
You had two problems "getc()" returns an integer not a character. And the while statement had some weird side effects in the original order.
It means the loop will fell into Infinite loop not allowing the program to exit when at a=getc(p).

Resources