C source code error in Caesar cipher - c

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.

Related

Please explain me this code if (input >= '0' && input <= '9') [duplicate]

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().

program to remove special characters and number from string and only print english letter

this is what i tried.
this works properly for small string like wel$co*me
but gives weird output for pass#word. where am i going wrong exactly?
#include <stdio.h>
#include <string.h>
int main()
{
char s[100],rs[100];
int i,c=0;
scanf("%s",s);
int n = strlen(s);
for(i=0;i<n;i++)
{
if(((int)s[i] >= 65 && (int)s[i] <= 90) ||((int)s[i] >=97 && (int)s[i] <= 122) )
{
rs[c] = s[i];
c++;
}
else
{
continue;
}
}
printf("%s",rs);
return 0;
}
but gives weird output for pass#word. where am i going wrong exactly?
printf("%s",rs); expects rs to be a pointer to a string. Yet without a certain null character in the data pointed to by rs, the result is undefined behavior or in OP's case, "weird output".
A simple solution is
rs[c] = '\0'; // add this after the loop
printf("%s",rs);
Another important one is to avoid buffer overruns - use a width limit.
// scanf("%s",s);
scanf("%99s",s);
Code has other weaknesses, yet this are the key ones for now.

How to detect space and letters in a Char in C?

Do you know how I can detect space and letters in a CHAR variable?
I need to detect letters or space in a input of numbers:
This what I want to do:
Enter Document Number of 8 numbers:
// i press space and pressed enter
ERROR: please enter the age again: 4fpdpfsg
There's where my code doesn't detect the letters after the 4, and what I want is recognize that there's letters in the input, and then shows only the 4.
int isLetter(char input[]){
int i = 0;
while(input[i]!='\0'){
if((input[i]!=' ') && (input[i]<'a'||input[i]>'z') && (input[i]<'A'||input[i]>'Z'))
return 0;
i++;
}
return 1;
}
The standard C library has various character type testing functions. They are declared in the #include <ctype.h> header.
Unfortunately, the obvious way of using these functions is often wrong. They take an argument of type int which is actually expected to be an unsigned character value (a byte, effectively) in the range 0 to UCHAR_MAX. If you pass in a char value which happens to be negative, undefined behavior ensues, which might work by coincidence, crash or worse yet form a vulnerability similar to heartbleed (possibly worse).
Therefore the cast to (unsigned char) is quite likely necessary in the following:
#include <ctype.h>
/* ... */
char ch;
/* ... */
if (isalpha((unsigned char) ch) || ch == ' ') {
/* ch is an alphabetic character, or a space */
}
Simple character constants (not numeric escaped ones) derived from the C translation time character set have positive values in the execution environment; code which can safely assume that it only manipulates such characters can do without the cast. (For instance, if all the data being manipulated by the program came from string or character literals in the program itself, and all those literals use nothing but the basic C translation time character set.)
That is to say, isalpha('a') is safe; a is in the C translation time character set, and so the value of the character constant 'a' is positive. But say you're working with source code in ISO-8859-1 and have char ch = 'à';. If char is signed, this ch will have a negative value, which is fine according to ISO C because an accented à isn't in the basic C translation character set. The expression isalpha(ch); then passes a negative value to the isalpha function, which is wrong.
Try:
if (!((input[i] == ' ') || (input[i] >= 'a' && input[i] <= 'z') || (input[i] >= 'A' && input[i] <= 'Z')))
or, better:
#include <ctype.h>
if (!((input[i] == ' ') || isalpha(input[i])))
You could use sscanf(input,"%d%n",&number,&nrOfDigits) which reads in an integral value into number and additionally stores the position of the first character which has not been part of the number in nrOfDigits. With this information, you can then decide what to do, e.g. nrOfDigits < 8 would indicate that either the input was shorter than 8 characters, or that it does contain less than 4 consecutive digits. See sample code of the usage below.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int isLetter(char input[]){
int nrOfDigits=0;
int number;
int scannedElems = sscanf(input,"%d%n",&number,&nrOfDigits);
if (scannedElems == 0) {// number could not be read--
printf ("No number read.\n");
return 0;
}
else {
char c = input[nrOfDigits];
int isAlpha = isalpha(c);
printf("input %s leads to number %d with %d digit(s); first characer after the digits is '%c', (isalpha=%d)\n", input, number, nrOfDigits, c, isAlpha);
return number;
}
}
int main(){
isLetter("4fpdpfsg"); // input 4fpdpfsg leads to number 4 with 1 digit(s); first characer after the digits is 'f', (isalpha=1)
isLetter("afpdpfsg"); // No number read.
isLetter("12345678"); // input 12345678 leads to number 12345678 with 8 digit(s); first characer after the digits is '�', (isalpha=0)
return 0;
}
BTW: you could implement a similar logic with strtoul as well.
hey guys i finally get the way to detect the input is conformed only for 8 numbers theres the code
char* InputDni(char dni[])
{
int sizeletter;
int i;
fflush(stdin);
gets(dni);
// 8 is the size of DNI in argentina
while((isLetter(dni)) || (strlen(dni)!=8))
{
printf("ERROR: enter again the DNI: ");
fflush(stdin);
gets(dni);
}
sizeletter=strlen(dni);
for(i=0 ;i<sizeletter; i++)
{
while(isalpha(dni[i]))
{
printf("ERROR: enter again the DNI: ");
fflush(stdin);
gets(dni);
i++
}
}
return dni;
}
//isLetter
int isLetter(char input[])
{
int i = 0;
int sizeletter;
int flag=1;
sizeletter=strlen(input);
for(i=0;i<sizeletter;i++)
{
if((input[i]!=' ') && (input[i]<'a'||input[i]>'z') && (input[i]<'A'||input[i]>'Z'))
{
flag=0;
}
}
return flag;
}
picture of the code running in cmd:

Switching case of each letter in a string

#include <stdio.h>
int main() {
int i;
char arr[100];
for (i = 0; i < 100; i++)
scanf("%c", &arr[i]);
for (i = 0; i < 100; i++) {
if ('a' <= arr[i] && arr[i] <= 'z')
arr[i] =-32;
else
if ('A' <= arr[i] && arr[i] <= 'Z')
arr[i] =+32;
}
printf("%s", arr);
return 0;
}
There was a problem:
You have been given a String consisting of uppercase and lowercase English alphabets. You need to change the case of each alphabet in this String. That is, all the uppercase letters should be converted to lowercase and all the lowercase letters should be converted to uppercase. You need to then print the resultant String to output.
What is wrong with the above code? It is compiling successfully but there is a runtime error.
There are multiple problems in your code:
the main issue is the away you adjust the case: arr[i] =-32; does not decrement arr[i] by 32, but stores 32 into arr[i]. The combined assignment operator is spelled -=. You have the same problem for += in the other case.
Converting lower case to upper case by subtracting 32 works for ASCII, but is not portable to other character sets. Similarly, comparing to 'a' and 'z' works for ASCII, but not for EBCDIC. You should use the functions from <ctype.h>.
you read 100 characters with scanf("%c"...) but you do not check the return value, nor do you null terminate the array. Furthermore, you should read at most one less than the size of the array to leave space for the '\0' byte. As coded, your program invokes undefined behavior at printf("%s", arr); because arr is not null terminated.
Here is a corrected version:
#include <ctype.h>
#include <stdio.h>
int main(void) {
int c;
while ((c = getchar()) != EOF) {
if (isupper(c))
c = tolower(c);
else
if (islower(c))
c = toupper(c);
putchar(c);
}
return 0;
}
The most obvious problem is that you are not null-terminating the string, so when you call printf("%s", arr) the behavior will be unpredictable.
The problem with your code is that it never terminates the string. If you read 100 characters, and then you want to print them with %s in printf, you have to add a null terminator at the end, like this:
char arr[100+1]; // See +1
... // Reading code
arr[100] = '\0';
Note that library functions islower/isupper provide a portable, and a lot more readable, approach to testing character type. Similarly, tolower/toupper provide more information about your intentions to the reader of your code than simply adding and subtracting 32. Moreover, C code that uses these standard functions will work on systems with non-ASCII character encoding.
In order to printf("%s", arr), you need to terminate arr with a null-character.
One way to do it is by:
Declaring char arr[101]
Setting arr[100] = 0
Your code has serveral issues: not-null-terminated input string, unproper lower/uppercase conversion and confusion with =- / -= and =+ / += operators.
Next code is based on yours:
As an alternative to get a null-terminated string it uses fgets() instead of scanf(), just for the example.
Also uses C library functions for avoiding issues with different charsets, simplifing the conditions and for upper/lower case operations.
Edited to improve code quality, as #chqrlie suggested in a comment.
#include <stdio.h>
#include <ctype.h>
int main()
{
int i;
char arr[101];
printf("Enter string: ");
fgets(arr, sizeof(arr), stdin);;
for(i=0;i<strlen(arr); i++)
{
int value = (unsigned char) arr[i]; // to properly use int parameters, as expected by ctype.h next functions
if (isupper(value))
{
arr[i]=tolower(value);
}
else {
if (islower(value))
{
arr[i]=toupper(value);
}
}
}
printf("%s", arr);
return 0;
}
Test it here.

is there a function to identify what letter is the char in a string C

i know there is isalpha(_) function for the string.h but i'm just wondering if there is a function for us to know what letter is the specific char in a string. and i want to change it with another specific char such as all A will become "#--" and all K will become "--#" and all other letters has its own differences (also is this possible? to make a substring? inside a string? or am i doing it wrong..)
char string[100];
int i;
char A*[]={"#--","--#"};
gets(string);
for(i=0, i<100, i++) {
if(isalpha(string[i])) {
string[i]=A[1];
}
}
but i don't know a function that tells me what letter that is.. i know it's a letter.. i know what letter is it.. but the computer/compiler doesn't know what letter is it, it just know if its a letter or not..
Can we also use the strcmp(_)? as an alternative? like if we make another char that we just put the whole alphabet letters in order?
char alpha[26]={'a','b','c','d','e','f','g','h','i','j','k','l'*you get the point* };
char string[100];
int i;
char A*[]={"#--","--#"};
gets(string);
for(i=0, i<100, i++) {
if(strcmp(alpha,string[i])==0) {
string[i]=A[1];
}
}
or should i use the ASCII table? because we tested it out
printf("%d , %d \n", 'A', 'a');
printf("%c, %c \n", 65, 97);
this out puts:
65 , 97
A , a
what is the best move to do here?
For this purpose, make yourself an array which contains the replacement characters. Then, access this array by the character you want to encode. Access is done by assuming that the char is an ASCII char, simply subtract the offset from the ASCII table (e.g. 65 if for letting it begin at A) and access your array. E.g.
char *code = [ '1', '2' ];
char input = 'B'; // 66 in ASCII
char output = code[input - 65];
Edit: of course you can do the same with e.g. char coding to char* (e.g. strings). Just use an array of strings instead of an array of characters.
char c = 'A' and char c = 65 is exactly the same thing.
If you want to compare 2 chars, just use the == operator:
char c = 'A';
char c2 = 65;
if (c == c2)
puts("It is equal!");
From this you can then create some functions/macro if you want to "abstract" the condition:
#define IS_LETTER(X, L) (X == L)
#define IS_LETTER_A(X) (IS_LETTER(X, 'A'))
char c = 'A';
if (IS_LETTER_A(c)) // or IS_LETTER(c, 'A')
puts("It's an A");

Resources