Program not encrypting properly with spaces - c

I have tried to create an implementation of a vigenere cipher, but have come across a hurde in the form of the program not working properly when given spaces in the input. (Assume keyword bacon)
With Spaces
Input
Meet me
Correct Output
Negh zf
Actual Output
Negh Ne
Without Spaces
Input
Meetme
Ouput
Neghzf
So clearly the program is working for strings without the spaces. Anywhere here is the code and thanks in advance for help.
#include <string.h>
#include <stdio.h>
#include <ctype.h>
char encrypt(int key, char a);
int hash(char a);
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("You need a keyword!");
return 1;
}
string keyword = argv[1];
for (int j = 0; j != strlen(keyword); ++j)
{
if (!isalpha(keyword[j]))
{
printf ("The keyword needs to be all words!");
return 1;
}
}
string text = GetString();
for (int i = 0, j = 0; i != strlen(text); ++i, ++j)
{
if (j == strlen(keyword))
{
j = 0;
}
int key = 0;
if (isupper(keyword[j]))
{
key = keyword[j] - 'A';
text[i] = encrypt(key, text[i]);
}
else if (islower(keyword[j]))
{
key = keyword[j] - 'a';
text[i] = encrypt(key, text[i]);
}
else if (isspace(text[i]))
{
j = j - 1;
}
}
printf ("%s\n", text);
}
char encrypt(int key, char a)
{
if (isalpha(a))
{
int total = (int) a + key;
if (isupper(a))
{
while (total > 90)
{
total = total - 26;
}
}
else if (islower(a))
{
while (total > 122)
{
total = total - 26;
}
}
return (char) total;
}
else
{
return a;
}
}

the problem is inside your for loop. Try to correct it in the following way (you will understand easily the mistake):
for (int i = 0, j = 0; i != strlen(text); ++i, ++j)
{
if (j == strlen(keyword))
{
j = 0;
}
// the following check mmust be done here
if (isspace(text[i])) {
j = j - 1;
}
int key = 0;
if (isupper(keyword[j]))
{
key = keyword[j] - 'A';
text[i] = encrypt(key, text[i]);
}
else if (islower(keyword[j]))
{
key = keyword[j] - 'a';
text[i] = encrypt(key, text[i]);
}
}

It looks like you are reading your words from command line arguments; however, command line arguments are typically separated by whitespace. Your program doesn't know that those spaces are supposed to be part of the input.
You need to change the way you are reading input.

Related

Core Dump (Segmentation fault) in this little encryption program I wrote in C for cs50

The error happens after the user enters the plaintext. I'm quite new to this language and programming itself. Help would be greatly appreciated. Since I am working in the cs50 codespace I cant use the debugger for some reason and cant see the code dump as one other question suggested I can solve the issue myself. Been at this for a few days and had to post a question now. Thanks.
bool no_repeat(string key, int l);
string cipher(string key, string input, int l);
int main(int argc, string argv[])
{
if (argc == 2)
{
string key = argv[1];
int l = strlen(key);
int ver = 0;
for (int i = 0; i < l; i++)
{
if (isalpha(key[i]))
{
ver++;
}
}
bool c = no_repeat(key, l);
if (strlen(argv[1]) == 0)
{
printf("Please enter an encryption key.\n");
return 1;
}
else if ((l != 26) || (ver != 26) || (c == false))
{
printf("Please input a correct encryption key.\n");
return 1;
}
}
else if (argc == 1)
{
printf("Please enter an encryption key.\n");
return 1;
}
string key = argv[1];
int l = strlen(key);
string input = get_string("plaintext:");
string cipherText = cipher(key, input, l);
printf("ciphertext: %s\n", cipherText);
return 0;
}
bool no_repeat(string key, int l)
{
for(int i = 0; i < l; i++)
{
for (int k = i+1; k < l; k++)
{
if (key[i] == key[k])
{
return false;
}
}
}
return true;
}
string cipher(string key, string input, int l)
{
string output = "";
string alphabets = "abcdefghijklmnopqrstuvwxyz";
for(int i = 0 ; i < l ; i++)
{
int isUpper = isupper(key[i]);
key[i] = tolower(key[i]);
for (int k = i ; k < l ; k++)
{
if (input[i] == alphabets[k])
{
output[i] = key[k];
}
else
{
output[i] = input[i];
}
}
if (isUpper != 0)
{
output[i] = toupper(output[i]);
}
}
return output;
}
string is probably a typedef char * string; and in that case you cannot modify string output = "";. Instead you want to use malloc() to allocate a string sufficiently large, i.e.:
string output = malloc(strlen(input) + 1);
if(!output) {
printf("malloc failed\n");
exit(1);
}
In cipher() you were also doing input[i] but i goes from 0 to strlen(key) so you will likely result in out of bound access. For me, cipher() was returning the input for ciphertext. Here is the fixed version (note, removed the argument l here and from caller as it's not needed):
string cipher(string key, string input) {
string output = malloc(strlen(input) + 1);
if(!output) {
printf("malloc failed\n");
exit(1);
}
const string alphabet = "abcdefghijklmnopqrstuvwxyz";
size_t j = 0;
for(size_t i = 0; i < strlen(input); i++, j++) {
string pos = strchr(alphabet, tolower(input[i]));
if(!pos) {
printf("letter %c not found in alphabet\n", input[i]);
exit(1);
}
output[j] = key[pos - alphabet];
}
output[j] = '\0';
return output;
}
and example execution:
~$ ./a.out abcdefghijklmnopqrtsuvwxzy # swap s and t
plaintext:test
ciphertext: sets
You don't have to store the alphabet, btw, as in ASCII pos - alphabet is the same value as tolower(input[i]) - 'a'.

Pset 2 CS50 Substitution Problem, If statement assigns variables(i guess)

I created a code for pset2 problem, named substitution in C.
The programs takes an String of Characters in command-line and apply it to a given text and changes it, printing the ciphertext.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{
//First part, checks KEY input
if (argc != 2) // checks quantity of command-line arguments
{
printf("Usage: ./substitution KEY\n");
return 1;
}
int i = 0;
int largo = strlen(argv[1]);
while (i < largo) //checks if char are alphabetic
{
if (isalpha(argv[1][i]) == 0)
{
printf("Key must contain only alphabetic characters\n");
return 1;
}
else //changes to uppercase
{
argv[1][i] = toupper(argv[1][i]);
}
i++;
}
if (i != 26) //checks length of Key
{
printf("Key must be 26 characters long\n");
return 1;
}
for (int j = 0; j < largo - 1; ++j) //checks repetition of characters
{
for (int k = j + 1; k < largo; ++k)
{
if (argv[1][j] == argv[1][k])
{
printf("Key must not have duplicated characters\n");
return 1;
}
}
}
//second part asks for input
//declaration of strings to get and transform
string plaintext = get_string("plaintext:");
string alfabeto = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string ciphertext = plaintext;
//third part: cifrado
for (int x = 0; x < strlen(plaintext); ++x)
{
if (isalpha(plaintext[x]) != 0)
{
int lower = 0;
if (islower(plaintext[x]) != 0) // is lower case?
{
lower = 1;
plaintext[x] = toupper(plaintext[x]);
}
for (int y = 0; y < strlen(alfabeto); ++y)
{
//printf("alfa: %c text: %c\n", alfabeto[y], plaintext[x]);
if (alfabeto[y] == plaintext[x])
{
ciphertext[x] = argv[1][y];
//printf("c: %s\n", ciphertext);
break;
}
}
if (lower == 1)
{
ciphertext[x] = tolower(ciphertext[x]);
}
}
}
printf("ciphertext: %s", ciphertext);
printf("\n");
return 0;
}
The issue is that the last if statement, kind of assigns the character in "ciphertext" to the "plaintext" variable, so i had to put a break statement in it, to stop that.
Any guesses why this program doesn't work as intended when there's no "break" statement?
if (alfabeto[y] == plaintext[x])
{
ciphertext[x] = argv[1][y];
//printf("c: %s\n", ciphertext);
break;
}

passing char array to function from scanf in c

I have following function in c code
void analyze_text(char text[]) {
...
for (int i = 0; i < text_length || text[i] != '\0'; i++) {
...
}
}
In main function i would like to pass some string to it. If i do something like this
char text[4000] = "some text here";
analyze_text(text);
this is cool and do the goal, but i would like to have some user input present and I am not sure how to get char[] out of it. I tried following 2 and none of them seemed to work:
char text[4000];
scanf("%s",text);
analyze_text(text);
OR
char text[4000];
int c;
int count=0;
c = getchar();
count = 0;
while ((count < 4000) && (c != EOF)) {
text[count] = c;
++count;
c = getchar();
}
analyze_text(text);
I know that the first one should return pointer to char array, but second one should return char array itself, or not?
Its been like 10 years since i havent been working with c/c++. Can anybody give me some hint please?
update (whole function):
void analyze_text(char text[]) {
int printable_text_length = 0;
int text_length = strlen(text);
int word_count = 0;
int sentence_count = 0;
int in_sentence = 0;
int in_word = 0;
int count[ASCII_SIZE] = { 0 };
for (int i = 0; i < text_length || text[i] != '\0'; i++) {
int c = text[i];
if (!isspace(c)) {
printable_text_length++;
}
if (isalpha(c)) {
in_word = 1;
in_sentence = 1;
count[tolower(c)]++;
}
if (text[i] == ' ' && text[i + 1] != ' ' && in_word==1) {
word_count++;
in_word = 0;
}
if (text[i] == '.' && in_sentence==1) {
sentence_count++;
in_sentence = 0;
}
}
if (in_word == 1) { word_count++; }
if (in_sentence == 1) { sentence_count++; }
char charIndexes[ASCII_SIZE];
for (int i = 97; i <= 122; i++) {
charIndexes[i] = i;
}
for (int i=97; i <= 122; i++) {
for (int j = i + 1; j <= 122; j++) {
if (count[i] > count[j]) {
int temp = count[j];
count[j] = count[i];
count[i] = temp;
int temp2 = charIndexes[j];
charIndexes[j] = charIndexes[i];
charIndexes[i] = temp2;
}
}
}
...printf...
}
The issue with
char text[4000];
scanf("%s",text);
analyze_text(text);
is that scanf identifies space-separated chunks, so you'll only read the first one.
In order to read up to a whole line from the user, try fgets:
char text[4000];
fgets(text, 4000, stdin);
analyze_text(text);
You may want to check the return value of fgets for error detection.
You can use dyanamic array of char to pass it into the function.
Here is the code
#include <stdio.h>
#include <stdlib.h>
void analyze_text(char* text) {
for (int i = 0; text[i] != '\0'; i++) {
printf("%c\n",text[i] );
}
}
int main() {
char* text = (char *)malloc(4000 * sizeof(char));
scanf("%s", text);
analyze_text(text);
return 0;
}
and here is the output with input = 'abhishek'
a
b
h
i
s
h
e
k
remember that strlen in dyanamc array will not give the length of input array.

Numbers in char array printing as random characters

So I'm writing a somewhat simple C program that is supposed to take a string of characters separated by semicolons as input. The program is then supposed to sort the strings by length and print them to the console.
Ex: abc;12;def;1234
The issue I'm having is that any numbers that are entered end up being printed as random symbols and I'm not sure why. I'm taking in input in this function:
void get_strings(char** c)
{
while (scanf("%[^;]s", c[numStrings]) != EOF)
{
getchar();
numStrings += 1;
}
}
Since scanf is looking for strings, if numbers are entered, are they stored as the 'character form' of those numbers, or should I be casting somehow?
Here's the rest of the code:
int numStrings = 0;
void sort_strings(char** c)
{
for (int i = 0; i < numStrings; i++)
{
for (int j = 0; j < numStrings - i; j++)
{
if (strlen(c[j]) > strlen(c[j + 1]))
{
char temp[1000];
strcpy(c[j], temp);
strcpy(c[j + 1], c[j]);
strcpy(temp, c[j + 1]);
}
}
}
}
void show_strings(char** c)
{
for (int i = 0; i < numStrings; i++)
{
if (printf("%s\n", c[i]) != EOF) break;
}
}
int main()
{
char wordLen[100][1000];
char* word2[100];
for (int i = 0; i < 100; i++)
{
word2[i] = wordLen[i];
}
char** words = word2;
get_strings(words);
sort_strings(words);
show_strings(words);
return 0;
}
The parsing code is incorrect:
void get_strings(char **c) {
while (scanf("%[^;]s", c[numStrings]) != EOF) {
getchar();
numStrings += 1;
}
}
the scanf() format contains an extra s that does not match the input.
the return value of scanf() should be compared to 1 to ensure successful conversion. Conversion failure produces EOF only at end of file, otherwise it produces 0 and the contents of c[numStrings] will be indeterminate.
conversion stops at the first character ;, this character stays in the input stream, but it is read by getchar(), yet if there is an empty field, the corresponding conversion would fail and the contents of the array would be indeterminate.
you should not use a global variable for the number of strings read. You should instead return this number.
The sorting code is incorrect too:
the inner loop runs one index too far: j + 1 must be less than numStrings for all runs.
the arguments to strcpy are passed in the wrong order.
strcpy should not be used at all, you should just swap the pointers.
show_strings() always stops after the first line as printf will return the number of characters printed.
You can fix the reading loop this way:
#include <stdio.h>
#include <string.h>
int get_strings(char **c, int maxStrings) {
int numStrings = 0;
while (numStrings < maxStrings) {
switch (scanf("%999[^;]", c[numStrings])) {
case 1:
getchar();
numStrings += 1;
break;
case 0:
if (getchar() == ';') {
c[numStrings] = '\0';
numStrings += 1;
}
break;
case EOF:
return numStrings;
}
}
}
void sort_strings(char **c, int count) {
for (int i = 0; i < count; i++) {
for (int j = 0; j < count - i - 1; j++) {
if (strlen(c[j]) > strlen(c[j + 1])) {
char *temp = c[j];
c[j] = c[j + 1];
c[j + 1] = temp;
}
}
}
}
void show_strings(char **c, int count) {
for (int i = 0; i < count; i++) {
printf("%s\n", c[i]);
}
}
int main(void) {
char words[1000][100];
char *wordPtrs[100];
int numStrings;
for (int i = 0; i < 100; i++) {
wordPtrs[i] = words[i];
}
numStrings = get_strings(wordPtrs, 100);
sort_strings(wordPtrs, numStrings);
show_strings(wordPtrs, numStrings);
return 0;
}

trying to use strcmp in if function for counting anagrams in a sentence

hii guys i need a serious help
i m trying to write a code for finding anagrams in input sentence
but when the if function is getting strcmp it stops and its not accepting the condition. any body know why is that happening
Basically my code supposed to do two things one is taking a sentence from the user and making the words appear in the Backwoods order two Its need to take the whole sentence and look for anagrams ( anagram means that there is the same letters but in a different order for example this and shit are anagrams) thank you very much for your help :)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main()
{
int index_for_word_start, words_num = 1,amount_of_letters;
int i, j, k;
char inpot_Sentence[1001], temp_letters;
char **words,**sorting_words;
int counter = 0,counter_max_for_anegram=0;
printf_s("Please enter the sentence, and then press Enter:\n");
gets(inpot_Sentence);
/////////////////////////////makeing the sentence backwards///////////////////////
for (i = 0; inpot_Sentence[i] != '\0'; i++) //loop for counting how many words(it will be use to know how many pointer we need)
{
if (inpot_Sentence[i] == ' ')
{
words_num++;
}
}
words = (char **)malloc(sizeof(char *)*words_num); //malloc for pointers that point on the pointer of the word
index_for_word_start = 0;
for (j = 0; j<words_num; j++)
{
for (i = index_for_word_start; inpot_Sentence[i] != ' '; i++)
{
if (!inpot_Sentence[i]) //if the user didnt put any word(break)
{
break;
}
}
words[j] = (char*)malloc(sizeof(char)*(i - index_for_word_start + 1)); //malloc of pointers that point on each word
strncpy_s(words[j], i - index_for_word_start+1, &inpot_Sentence[index_for_word_start], i - index_for_word_start); //copy the words from inpot sentence to array
words[j][i - index_for_word_start] = 0; //puts '\0' after the word copy ends
index_for_word_start = i + 1;
}
printf_s("\nThe reverse sentence is:\n");
for (i = words_num - 1; i >= 0; i--) //print the words in backwards Sequence
{
printf("%s ", words[i]);
}
putchar('\n');
i = 0;
/////////////////////anegrams check///////////////////////
for (j = 0; j < words_num; j++) //loops that Arrange the array by haski value
{
amount_of_letters = strlen(words[j]);
for ( i = 0; i < amount_of_letters; i++)
{
for (k = 0; k < amount_of_letters; k++)
{
if (words[j][i]<words[j][k])
{
temp_letters = words[j][i];
words[j][i] = words[j][k];
words[j][k] = temp_letters;
}
}
}
printf_s("this is words %s\n", words[j]);
}i = 0;
for ( j = 0; j < words_num-1; j++)
{
for ( i = 0; i < words_num-1; i++)
{
if (!strcmp(words[j],words[i]) && (i!=j) && (strcmp(words[j],"\0")))
{
counter++;
words[i] = 0;
}
else
{
break;
}
}
if (counter>counter_max_for_anegram)
{
counter_max_for_anegram = counter;
}
counter = 0;
}
printf_s("%d\n", counter_max_for_anegram);
for ( j = 0; j < words_num; j++)
{
free(words[j]);
}
free(words);
}
#include <stdio.h>
#include <string.h>
int check_anagram(char[],char[]);
int main()
{
char a[100],b[100];
int flag;
puts("Enter the first string");
fgets(a,100,stdin);
a[strcspn(a, "\r\n")] = '\0';
puts("Enter the second string");
fgets(b,100,stdin);
b[strcspn(b, "\r\n")] = '\0';
flag=check_anagram(a,b);
if(flag)
printf("%s and %s are anagrams",a,b);
else
printf("%s and %s are not anagrams",a,b);
}
int check_anagram(char a[], char b[])
{
int first[26]={0},second[26]={0},c=0;
while(a[c]!='\0')
{
first[a[c]-'a']++;
c++;
}
c=0;
while(b[c]!='\0')
{
second[b[c]-'a']++;
c++;
}
for(c=0;c<26;c++)
{
if(first[c]!=second[c])
return 0;
}
return 1;
}

Resources