why the program omitted some lines? (c program to encrypt text) - c

i am trying to make a program that encrypt text with a Caesar cipher.The number of positions to shift will be given to the program as a command line argument and characters other than letters should not be encrypted. The program should stop only at the end of input. My issue is that the program omit the lines that mod the number. the program is run on a platform that provided by my school, i am not sure what it is. please kindly help me to fix the program.
here is my program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( int argc, char *argv[] ) {
int num = atoi(argv[1]);
char caesar[100];
char ch;
int shift = num%26;
while ( fgets(caesar, 100, stdin) != NULL){
for(int i = 0; i < strlen(caesar); i++){
ch = caesar[i];
if( ch >= 97 && ch <= 122){
if( ch + shift < 97){
ch = ch + shift + 26;
}
else if( ch + shift > 122){
ch = ch + shift - 26;
}
else{
ch = ch + shift;
}
caesar[i] = ch;
}
else if( ch >= 65 && ch <= 90){
if( ch + shift < 65){
ch = ch + shift + 26;
}
else if( ch + shift > 90){
ch = ch + shift - 26;
}
else{
ch = ch +shift;
}
caesar[i] = ch;
}
}
}
printf("%s", caesar);
return 0;
}
here is some examples which have correct output
here is what my program did. the program ignored shift = num%26 and i can't figure out why

Related

I can't figure out how to use the strlen in my C code

I just started learning C. I am supposed to create a password program where the user inputs strings that are at least 8 characters longs. It also needs to have one upper case, one lower case, one digits, and one symbol from this set {#, %, +}. I can't try to figure out the loop where it prints invalid when the user doesn't type in at least 8 characters. I tried using strlen but it gives me an error passing argument 1 of ‘strlen’ makes pointer from integer without a cast can someone help me?
#include <stdio.h>
#include <string.h>
int main()
{
int n;
int k;
char ch;
unsigned char uFlag = 0, cFlag = 0, dFlag = 0, hFlag = 0, aFlag = 0;
printf("Enter a password: ");
ch = getchar();
n = strlen(ch);
k = n - 1;
while (ch != '\n')
{
if(ch >= 'A' && ch <= 'Z')
uFlag = 1;
else if(ch >= 'a' && ch <= 'z')
cFlag = 1;
else if(ch >= '0' && ch <= '9')
dFlag = 1;
else if(ch == '#' || ch == '%' || ch == '+')
hFlag = 1;
else if (k >= 8)
aFlag = 1;
ch = getchar();
}
if (uFlag == 1 && cFlag == 1 && dFlag == 1 && hFlag == 1 && aFlag == 1)
{
printf("Password entered is valid.\n");
}
else
{
printf("Password entered is invalid.\n");
}
return 0;
}
char ch; defines a variable for a single character, not for a string. So you cannot use strlen(ch), because strlen expects a pointer to a string (and not a single character).
As you are reading in one character after another with ch = getchar() in a loop, you actually do not compose any string. The only thing you need to do is increment k with each iteration:
k = 0;
while (ch != '\n')
k++;
...
ch = getchar();
}
You must be used an array of characters and not an char. In your code, you have written -
n = strlen(ch);
However, strlen() accepts char* or an array of character or pointer to a string as parameter. You are passing ch which is of type char and is the wrong parameter data type. This is main reason why you are getting the error.
I have made minor edits in your program which you can refer below -
#include <stdio.h>
#include <string.h>
int main()
{
int i=0; //i to maintain current index in char array-ch
char ch[100],c; //or you could use dynamic allocation by asking user for input, c will read user input
unsigned char uFlag = 0, cFlag = 0, dFlag = 0, hFlag = 0, aFlag = 0;
printf("Enter a password: ");
c = getchar(); //read the input into character as you did
ch[i]=c; //assign the character to current index in ch array
while (ch[i] != '\n') //check until user hits enter
{
if(ch[i] >= 'A' && ch[i] <= 'Z')
uFlag = 1;
else if(ch[i] >= 'a' && ch[i] <= 'z')
cFlag = 1;
else if(ch[i] >= '0' && ch[i] <= '9')
dFlag = 1;
else if(ch[i] == '#' || ch[i] == '%' || ch[i] == '+')
hFlag = 1;
//the below should be if and not if else as in your posted code for it to work as expected
if (i >= 8) // sets the flag once length of array get over 8
aFlag = 1;
i++; // first increment index since we have already read at current index
c = getchar(); //same as before
ch[i] = c;
}
if (uFlag == 1 && cFlag == 1 && dFlag == 1 && hFlag == 1 && aFlag == 1)
{
printf("Password entered is valid.\n");
}
else
{
printf("Password entered is invalid.\n");
}
return 0;
}
Hope this solves your problem !
regarding:
ch = getchar();
n = strlen(ch);
the function getchar() only inputs a single char, not a string.
the function strlen() expects a NUL terminated array of characters.
Suggest inputting the password using;
fgets( buffer, sizeof( buffer ), stdin );
rather than using many calls to getchar()
then use:
buffer[ strcspn( buffer, "\n" ) ] = '\0';
to remove an newline character
then looping through the buffer[], checking each character
for( size_t i=0; buffer[i]; i++ )
{
// perform all the needed checks of the password
}

Circular shift cipher

I have written a circular shift cipher for key -1 billion to +1 billion for encrypting messages of maximum 200 characters including 0 to 9, a to z and A to Z.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char input[215], key[11], msg[201], output[201], ch;
int i, j, k, shiftkeychar, shiftkeynum;
printf("Input: ");
gets(input);
for (i = 0; input[i] != ':'; i++)
key[i] = input[i];
key[i] = '\0';
i++;
k = 0;
for (j = i; input[j] != '\0'; j++) {
msg[k] = input[j];
k++;
}
msg[k] = '\0';
printf("\nmessage: %s\n", msg);
printf("key: %s\n", key);
shiftkeychar = atoi(key) % 26;
shiftkeynum = atoi(key) % 10;
printf("shiftkey for characters: %d\n", shiftkeychar);
printf("shiftkey for numbers: %d\n", shiftkeynum);
strcpy(output, msg);
for (i = 0; output[i] != '\0'; i++) {
ch = output[i];
if (ch >= 'A' && ch <= 'Z') {
ch = ch + shiftkeychar;
if (ch > 'Z') {
ch = ch - 'Z' + 'A' - 1;
}
else if (ch < 'A') {
ch = ch + 'Z' - 'A' + 1;
}
}
else if (ch >= 'a' && ch <= 'z') {
ch = ch + shiftkeychar;
if (ch > 'z') {
ch = ch - 'z' + 'a' - 1;
}
else if (ch < 'a') {
ch = ch + 'z' - 'a' + 1;
}
}
else if (ch >= '0' && ch <= '9') {
ch = ch + shiftkeynum;
if (ch > '9') {
ch = ch - '9' + '0' - 1;
}
else if (ch < '0') {
ch = ch + '9' - '0' + 1;
}
}
output[i] = ch;
//printf("output[%d]: %c", i, ch);
}
printf("Output: %s", output);
return 0;
}
This Circular shift cipher is working well for Capital letters and digits. However for small letters e.g. if message is 'xyz' and key is more than 5 (i.e., 6,7,...25) its generating some arbitrary output. input format is: "key:message". output is:"encrypted message".
Your character ch is a char, which in C may or may not be signed. On your machine, it seems to be signed, which means that you can store values from −128 to 127. The lower-case letters occupy the ASCII codes from 97 to 122. When you say:
ch = ch + shiftkeychar;
you may overflow the signed char for letters at the back of the alphabet. Technically, this is undefined behaviour; in practice you will probably get negative values, which will lead to strange characters later on.
To resolve your problem, make ch an int.

Caesar Cipher Negative Numbers Issue

I'm trying to write a caesar cipher program that takes an argument, converts it into an integer, and uses that as to shift the letters in a certain direction (positive numbers shift it forward and negative numbers shift it backwards. So far all the program works for all positive numbers but does not for negative numbers.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int encrypt(int character, int shift);
int main(int argc, char * argv[]) {
int shift = atoi(argv[1]);
if (shift >= 26) {
shift = ((shift + 26) % 26);
}
int character = getchar();
while (character != EOF) {
int new_character = encrypt(character, shift);
putchar(new_character);
character = getchar();
}
return 0;
}
int encrypt(int character, int shift) {
int ch = character;
int negShift = shift;
if (ch >= 'a' && ch <= 'z') {
ch = ch + shift;
if (ch > 'z') {
ch = ch - 'z' + 'a' - 1;
}
} else if (ch >= 'A' && ch <= 'Z') {
ch = ch + shift;
if (ch > 'Z') {
ch = ch - 'Z' + 'A' - 1;
}
}
return ch;
}
You could just add the 26 to ch when ch < 'a' or ch <'A'.
Consider below example.
if(ch < 'a')
{
ch = ch + 26;
}
Full code.
int encrypt(int character, int shift) {
int ch = character;
int negShift = shift;
if (ch >= 'a' && ch <= 'z') {
ch = ch + shift;
if (ch > 'z') {
ch = ch - 'z' + 'a' - 1;
}
else if(ch < 'a')
{
ch = ch + 26; //Here
}
} else if (ch >= 'A' && ch <= 'Z') {
ch = ch + shift;
if (ch > 'Z') {
ch = ch - 'Z' + 'A' - 1;
}
else if(ch < 'A')
{
ch = ch + 26; // Here
}
}
return ch;
}

Get whole number from input using only getchar() and convert to int

For a school assignment i have to make a C program that reads a whole number, that may be preceded by a '+' or '-'. i can only use getchar().
I can convert a single char to an int using int i = ch - '0' but I want to read in multiple chars. besides that I need to check if the input is correct (eq. no not-numerical charachters)
I have this so far:
int main(void) {
int i;
char ch;
printf("voer een getal in: ");
while ((ch = getchar()) != '\n') {
i = ch - '0';
}
printf("het ingevoerde getal is: %d\n", i);
return EXIT_SUCCES;
}
Edit: I get that this isn't really the place for problems like this (I should learn to fix it myself, not get others to fix it for me) but I didn't know what to do anymore. thanks you for guiding me to the right path
This should get you started:
int main(void) {
int i = 0;
int ch;
printf("voer een getal in: ");
while ((ch = getchar()) != '\n') {
if (ch > '9' || ch < '0')
continue; // or print an error and exit
i *= 10;
i += ch - '0';
}
printf("het ingevoerde getal is: %d\n", i);
return EXIT_SUCCES;
}
I'll leave detecting the potential + / - sign as an exercise.
If your school allows you to use shift operators then here is a quick way to get integer from the user and as per their requirements you can show the + or - sign preceding the integer. But remember not to just copy paste it. Understand the code first.
int main(){
int i = 0;
char c;
char sign = 43;
printf("voer een getal in:\n");
c = getchar();
if(c == 45)
sign = 45;
for(; (c<48 || c>57); c = getchar());
for(; c>47 && c<58 ; c = getchar()){
i = (i<<1) + (i<<3) + c - 48;
}
printf("het ingevoerde getal is: %c%d\n",sign, i);
return 0;
}
Reading in multiple characters, and determine whether positive, negative, and value:
int sign = 1;
ch = getchar(); //look at first char (might be a sign indicator)
if((ch == '-') || (ch == '+')) //consume first char if either `-` or `+`
{
if(ch == '-') sign = -1;
}
else //first char non-sign - handle as digit
{
if (ch > '9' || ch < '0')
continue; // or print an error and exit
i *= 10;
i += ch - '0';
}
while ((ch = getchar()) != '\n') //get remaining chars (assume no embedded sign chars)
{
if (ch > '9' || ch < '0')
continue; // or print an error and exit
i *= 10;
i += ch - '0';
}
i *= sign; //apply sign to value
I think this will work.
while ((ch = getchar()) != '\n') {
i = ch - '0' + i * 10;
The problem in your code is that you are overwriting i every time you read a new character. You need to store the digit you read, and then add to it.
You should take care about not number characters :
while((ch=getchar()) != '\n')
if(ch >= '0' && ch <= '9')
i += 10* i + (ch - '0');
For the '-' or '+' at the begining you could store the first getchar(). A solution could be :
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int i = 0;
char ch,first_ch;
printf("voer een getal in: ");
ch = first_ch = getchar();
while (ch != '\n') {
if(ch >= '0' && ch <= '9')
i = 10* i + (ch - '0');
ch = getchar();
}
if(first_ch == '-')
i *= -1;
printf("het ingevoerde getal is: %d\n", i);
return EXIT_SUCCESS;
}

About Rot13-Implementation

I am trying to implement the rot13-algorithm in C.
But since I am not very familiar with that language, I have some problems with my code right here.
Basically, I want to rotate every letter in args[] to 13 positions up.
But this code seems to be pretty sluggish:
#include <stdio.h>
char[] rotate(char c[]) {
char single;
int i;
int alen = sizeof(c)/sizeof(c[0]);
char out[alen];
for(i=0;i<=alen;i+=1) {
if(c[i]>='a' && (c[i]+13)<='z'){
out[i] = c[i]+13;
}
}
return out;
}
int main(int argc, char *argv[]) {
printf("The given args will be rotated\n");
int i;
char rotated[sizeof(argv)/sizeof(argv[0])];
rotated = rotate(argv);
/* printing rotated[] later on */
return 0;
}
I know there a lot of holes here - could you show me how to fix this?
Thanks a lot guys, I solved the problem with this code
#include <stdio.h>
int rot13(int c){
if('a' <= c && c <= 'z'){
return rot13b(c,'a');
} else if ('A' <= c && c <= 'Z') {
return rot13b(c, 'A');
} else {
return c;
}
}
int rot13b(int c, int basis){
c = (((c-basis)+13)%26)+basis;
return c;
}
int main() {
printf("The given args will be rotated");
int c;
while((c = getchar()) != EOF){
c = rot13(c);
putchar(c);
}
return 0;
}
How #Michael said this char out[alen] is not accepted by the compiler because you can't declare an array size with a non constant value. Another problem of your code is the for loop for( i = 0; i < = alen; i+=1 ) the arrays start on 0 so if you do the for until the lenght's position you will be out of the array.
About the code:
You must use a pointer to the start of the string as argument of the function, because You can't return arrays in C (But you can return pointers ).
Your if( str[i] >= 'a' && (str[i]+13) <='z') is incorrect because you will convert some letters into symbols take a look.
________
--------------------------!
void rotate( char * str )
{
int i = 0;
/* You do this until you find a '\0' */
for( i = 0; str[ i ] != '\0' ; i++ ){
/* Use the pointer notation if you passed a pointer. */
/* If the letter is between a and m you can simply sum it. */
if( *( str + i ) >= 'a' && *( str + i ) < 'n')
*( str + i ) += 13;
/* If the letter is between the n and z you have to do the opposite.*/
else if( *( str + i ) >= 'n' && *( str + i ) <= 'z')
*( str + i ) -= 13;
}
}
Size of arrays in C must be set at compile time, so you can't use non constant expression for array size.
Consider the below implementation:
// in place rotate
void rotate(char *str)
// str must be a zero-terminated string
{
int i =0;
// loop until str itself is not NULL and str[i] is not zero
for(i=0;str && str[i]; ++i) // ++i is a pre-increment
{
if(str[i] >= 'a' && (str[i]+13) <='z')
{
str[i] = str[i]+13; // modifying str in place
}
}
}
Then your main() can look like this:
int main(int argc, char *argv[])
{
printf("The given args will be rotated: %s\n", argv[1]);
rotate(argv[1]);
printf("Rotated: %s\n", argv[1]);
return 0;
}
Update More advanced version of the transform that takes care of case when str[i] + 13 > 'z'
for(i=0;str && str[i]; ++i) // ++i is a pre-increment
{
// ignore out of range chars
if (str[i] < 'a' || str[i] > 'z') continue;
// rotate
for (off = 13; off > ('z' - str[i]); )
{
off-= (1 + 'z' - str[i]);
str[i] = 'a';
}
str[i]+=off;
}
This function can encode/decode to/from rot13 string. It's compatible with VIM's g? rot13 encoder.
void rot13 (char *s) {
if (s == NULL)
return;
int i;
for (i = 0; s[i]; i++) {
if (s[i] >= 'a' && s[i] <= 'm') { s[i] += 13; continue; }
if (s[i] >= 'A' && s[i] <= 'M') { s[i] += 13; continue; }
if (s[i] >= 'n' && s[i] <= 'z') { s[i] -= 13; continue; }
if (s[i] >= 'N' && s[i] <= 'Z') { s[i] -= 13; continue; }
}
}

Resources