I'm trying to make a simple encryption program with C. My aim is to translate abc (it can be any word) to 123. Then multiply 2 and get 246 then again translate to text, then write on screen bdf. Here is my algorithm which is not working correctly. I entered abc and I got cbc. Can you help me?
int main()
{
int z,o,c,l,i,j,k,*D;
char word[10];
char alfabe[24]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','r','s','t','u','v','y','z','\0'};
printf("enter word");
scanf("%s",word);
c=strlen(word);
printf("has %d letters ", c);
D = (int *) malloc( sizeof(int)*c );
for(i=0;i<c;i++) {
for(j=0;j<26;j++) {
if(word[i]==alfabe[j]) {
D[i]=2*(j+1);
break;
}
}
}
printf("\nlast form before translation ");
for(l=0;l<c;l++) {
printf("%d",D[l]); /*it s just for control */
}
for(z=0;z<c;z++){
printf("%c",alfabe[o]);
o=D[z];
word[z]=alfabe[o] ; break; }
printf("\nnew form of word: ");
for(k=0;k<c;k++) {
printf("%c",word[k]);
}
scanf("%d");
}
The problem is in the following loop.
for(z=0;z<c;z++){
printf("%c",alfabe[o]);
o=D[z];
word[z]=alfabe[o] ;
break;
}
Why did you break? It just translates first character. Second, you need to subtract 1 to get the right index of alphabet array(to redo the addition you did).
word[z]=alfabe[o-1];
Third, you are using o before initializing it? Your compiler should warn you for this.
Fourth, why are you storing 27 characters in char array of size 24?
char alfabe[24]={'a','b',...........,'\0'}
And last but not least you need to use modular arithmetic, this wont work if user enters something like xyz.
OK, first of all '\0' marks the end of an inputed string, you don't need to encrypth this particular character, my suggestion is to place it first in the alfabet so you would get:
alfabet[24] = {'\0', 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','r','s','t','u','v','y','z'};
This will save you the trouble of substracting 1, so you will have:
for (i = 0; i < c; i++)
{
for (j = 0; j < 24; j++)
{
if (word[i] == alfabet[j])
{
D[i] = 2 * j;
}
}
}
In the part where you encode the input. And when you generate the output word:
for (z = 0; z < c; z++)
{
printf("%c", alfabet[D[z]]);
word[z] = alfabet[D[z]];
}
No need for o and especially no break; in the loop.
A more efficient way would be to create a function that handles the encryption of the string passed:
char* getEncryptedWord(char* word)
{
char alfabet[25]={'\0', 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','r','s','t','u','v', 'x', 'y','z'};
int i, j;
int size = strlen(word);
char* encryptedWord = (char*) malloc(size + 1);
for (i = 0; i < size; i++)
{
for (j = 0; j <= 25; j++)
{
if (word[i] == alfabet[j])
{
if (2 * j > 25)
encryptedWord[i] = alfabet[2 * j % 25];
else
encryptedWord[i] = alfabet[2 * j];
break;
}
}
}
encryptedWord[size] = '\0';
return encryptedWord;
}
I've added 'x' in the alfabet - that is the reason why now there are 25 elements. I'm sure there is one character of the English alphabet missing, but it's 3 AM here and English isn't my primary language. Also, this solution is working on the assumption that the alfabet you provided are the only characters that are supposed to exist in the input and output.
(tip: If you only expect letters A-Z, you don't need to loop through the array to find the corresponding number, you may simply get the number by subtracting the numerical value of 'a', and add 1, if you want the letter 'a' to map to 1.)
Modulo arithmetic is mentioned, but that will give you problems because you will loose the 1:1-mapping, i.e. two letters can end up being translated to the same number.
Related
My professor asked me to make a Codebreaker game in C. (User is breaking the code by guessing original code. original code is given as a cmd-line arg.After every attempt;(b, w): the number of correct colors in the correct positions (b) and the number of colors that are part of the code but not in the correct positions (w) are printed as Feedback.)Only standard input and output is allowed. I got it working, but the arrays Secret_Code2 and guess2 goes out of bounds. It has some strange behaviours like changing int variables causes changes in arrays even they are independent. I'm aware that C does not check array bounds, is there any improvements that i can make?
Here is my code;
#include <stdio.h>
#define Max_Attempts 12
char *Sectret_CODE = NULL;
int main(int argc,char **argv)
{
//Definitions
printf("Available Colors: (B)lue (G)reen (O)range (P)urple (R)ed (Y)ellow\n\n");
//Getting input and validating
if(argc != 2)
{
fprintf(stderr,"Invalid input\n");
return 1;
}
Sectret_CODE = argv[1];
int i = Max_Attempts;
int Won = 0;
while (i > 0 && !Won)
{
int b = 0, w = 0, t=0;
char guess[4];
char Sectret_CODE2[4];
char guess2[4];
printf("No. guesses left: %i\n",i);
printf("Enter Your Guess: ");
scanf("%s",guess);
//printf("%s",guess);
for(int j = 0; j < 4; j++)
{
//printf("%s,%s\n",Sectret_CODE2,guess2);
if(Sectret_CODE[j] == guess[j])
{
b++;
}
else
{
Sectret_CODE2[t] = Sectret_CODE[j];
guess2[t] = guess[j];
t++;
printf("%s,%s,%i\n",Sectret_CODE2,guess2,t);
}
}
int s = t;
//printf("%i",t);
Sectret_CODE2[t] = '\0' ;
guess2[t] = '\0' ;
if(b == 4)
{
printf("You Won\n");
Won = 1;
return 0;
}
else
{
for(int j = 0; j < s; j++)
{
for(int k = 0; k < s;k++)
if(Sectret_CODE2[j] == guess2[k])
{
w++;
break;
}
}
}
printf("Feedback: %i,%i\n",b,w);
i--;
}
if(!Won)
{
printf("You Lose!\n");
}
}
You aren't allocating space for the terminating null character in your character arrays. Each array needs to hold up to 4 values, plus a terminating null character. So you need to declare them to hold 4+1 = 5 characters. Otherwise writing the null character can write past the end of the arrays.
Also, inside your loop, you are attempting to print those arrays using printf with %s before null-terminating them. You need to null-terminate them, at the proper point, before printing them with %s.
I'm having trouble with trying to manipulate 2d dynamic arrays in C. What I want to do is to store a char string in every row of the the 2d array then perform a check to see if the string contains a certain character, if so remove all occurrences then shift over the empty positions. What's actually happening is I get an exit status 1.
More about the problem, for example if I have
Enter string 1: testing
Enter string 2: apple
Enter string 3: banana
I would want the output to become
What letter? a // ask what character to search for and remove all occurences
testing
pple
bnn
Here is my full code:
#include <stdio.h>
#include <stdlib.h>
void removeOccurences2(char** letters, int strs, int size, char letter){
// Get size of array
// Shift amount says how many of the letter that we have removed so far.
int shiftAmt = 0;
// Shift array says how much we should shift each element at the end
int shiftArray[strs][size];
// The first loop to remove letters and put things the shift amount in the array
int i,j;
for(i=0;i < strs; i++){
for(j = 0; j < size - 1; j++) {
if (letters[i][j] == '\0'){
break;
}
else {
// If the letter matches
if(letter == letters[i][j]){
// Set to null terminator
letters[i][j] = '\0';
// Increase Shift amount
shiftAmt++;
// Set shift amount for this position to be 0
shiftArray[i][j] = 0;
}else{
// Set the shift amount for this letter to be equal to the current shift amount
shiftArray[i][j] = shiftAmt;
}
}
}
}
// Loop back through and shift each index the required amount
for(i = 0; i < strs; i++){
for(j = 0; j < size - 1; j++) {
// If the shift amount for this index is 0 don't do anything
if(shiftArray[i][j] == 0) continue;
// Otherwise swap
letters[i][j - shiftArray[i][j]] = letters[i][j];
letters[i][j] = '\0';
}
//now print the new string
printf("%s", letters[i]);
}
return;
}
int main() {
int strs;
char** array2;
int size;
int cnt;
int c;
char letter;
printf("How many strings do you want to enter?\n");
scanf("%d", &strs);
printf("What is the max size of the strings?\n");
scanf("%d", &size);
array2 = malloc(sizeof(char*)*strs);
cnt = 0;
while (cnt < strs) {
c = 0;
printf("Enter string %d:\n", cnt + 1);
array2[cnt] = malloc(sizeof(char)*size);
scanf("%s", array2[cnt]);
cnt += 1;
}
printf("What letter?\n");
scanf(" %c", &letter);
removeOccurences2(array2,strs,size,letter);
}
Thanks in advance!
You can remove letters from a string in place, because you can only shorten the string.
The code could simply be:
void removeOccurences2(char** letters, int strs, int size, char letter){
int i,j,k;
// loop over the array of strings
for(i=0;i < strs; i++){
// loop per string
for(j = 0, k=0; j < size; j++) {
// stop on the first null character
if (letters[i][j] == '\0'){
letters[i][k] = 0;
break;
}
// If the letter does not match, keep the letter
if(letter != letters[i][j]){
letters[i][k++] = letters[i][j];
}
}
//now print the new string
printf("%s\n", letters[i]);
}
return;
}
But you should free all the allocated arrays before returning to environment, and explicitely return 0 at the end of main.
Well, there are several issues on your program, basically you are getting segmentation fault error because you are accessing invalid memory which isn't allocated by your program. Here are some issues I found:
shiftAmt isn't reset after processing/checking each string which lead to incorrect value of shiftArray.
Values of shiftArray only set as expected for length of string but after that (values from from length of each string to size) are random numbers.
The logic to delete occurrence character is incorrect - you need to shift the whole string after the occurrence character to the left not just manipulating a single character like what you are doing.
1 & 2 cause the segmentation fault error (crash the program) because it causes this line letters[i][j - shiftArray[i][j]] = letters[i][j]; access to unexpected memory. You can take a look at my edited version of your removeOccurences2 method for reference:
int removeOccurences2(char* string, char letter) {
if(!string) return -1;
int i = 0;
while (*(string+i) != '\0') {
if (*(string+i) == letter) {
memmove(string + i, string + i + 1, strlen(string + i + 1));
string[strlen(string) - 1] = '\0'; // delete last character
}
i++;
}
return 0;
}
It's just an example and there is still some flaw in its logics waiting for you to complete. Hint: try the case: "bananaaaa123"
Happy coding!
"...if the string contains a certain character, if so remove all occurrences then shift over the empty positions."
The original string can be edited in place by incrementing two pointers initially containing the same content. The following illustrates.:
void remove_all_chars(char* str, char c)
{
char *pr = str://pointer read
char *pw = str;//pointer write
while(*pr)
{
*pw = *pr++;
pw += (*pw != c);//increment pw only if current position == c
}
*pw = '\0';//terminate to mark last position of modified string
}
This is the cleanest, simplest form I have seen for doing this task. Credit goes to this answer.
This program is meant to sort words alphabetically, either words that are imputed into it, or from a text file. It compiles just fine, but when I run it, I get a large mass of text. Here is a small sample of it:
:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:
v=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:
It kinda looks like some file formats or something?
This is followed by the words:
Segmentation fault (core dumped)
I'm compiling in GCC on Ubuntu.
The program is:
#include <stdio.h>
#include <string.h>
#define MO 109 // 109 is ASCII for "m".
#define FO 102 // 102 is ASCII for "f".
#define OO 101 // 101 is ASCII for "e" and denotes an error.
int main() // Main part of program.
{
int i, j; // Counter integer assignment.
int n = 100; // assignment of integer for the number of strings.
char a; // For the m/f (manual or file) option.
char str[100][100]; // Str is the main string to be sorted.
char temp[100]; // Temp is to switch the values for bubble sorting.
for(i = 0; i < 1; a = OO)
{
printf("To input text manually, press m. To sort a file, press f. \n");
// M/f option.
scanf("%c", &a); // Gets m/f option.
if(a == MO || a == FO) // Checks for valid input.
{
i = 2; // Escape from loop with valid input.
}
if(a != MO && a != FO) // Invalid input.
{
printf("Please insert a valid response. ");
i = 0; // Continue loop until a valid input is reached.
}
}
if(a == MO) // Manual insert option.
{
puts("Enter the number of strings to be sorted.");
scanf("%d", &n); // Gets number of strings.
for(i = 0; i <= n; i++)
{
gets(str[i]); // Gets strings from user.
}
}
if(a == FO) // File option.
{
char b[100]; // File address of text file to be sorted.
FILE * f; // Text file.
printf("Enter file path of file to be sorted.");
scanf("%c", b); // Gets file path.
f = fopen(b, "r"); // Opens file.
fgets(*str, 100, f); // Coverts file into string str.
fclose(f); // Closes file.
}
for(i = 0; i <= n; i++) // Begin bubble sort.
{
for(j = i + 1; j <= n; j++)
{
if(strcmp(str[i], str[j]) > 0) // Checks alphabetical value.
{
strcpy(temp, str[i]); // Switch two strings.
strcpy(str[i], str[j]);
strcpy(str[j], temp);
}
}
}
printf("The sorted string:");
for(i = 0; i <= n; i++)
{
puts(str[i]); // Prints final output.
}
return 0; // End of main.
}
A Google search told me that a segmentation fault usually means that I'm referring to a place in the memory that doesn't exist. But I couldn't find any advice on how to fix it, or even what the problem is specifically.
If someone could help me out with this I would really appreciate it. Thanks.
As one of the comments to your question says, there are many things wrong with the code...
For example
for(i = 0; i < 1; a = OO)
{
// ...
}
At the end of that loop, a == OO always, because you tell it to equal OO in the last part of the for statement. So all your work to set the value of a inside the 'loop' is wasted.
But getting back to the point of the question, about the seg-fault: You're right that it's caused by referring to memory that your program doesn't own. In your case, it's probably because of this:
int n = 100; // assignment of integer for the number of strings.
// ...
char str[100][100]; // Str is the main string to be sorted.
// ...
for(i = 0; i <= n; i++) // Begin bubble sort.
{
for(j = i + 1; j <= n; j++)
{
if(strcmp(str[i], str[j]) > 0) // Checks alphabetical value.
str[100] is beyond the limits of your array. An array with 100 elements will use indicies from 0 to 99. str[100] would access the '101st' element, which is out of bounds and thus can cause a seg fault.
I did a small modification to your algorithm and it works for me:
#include <stdio.h>
#include <string.h>
#define MO 109 // 109 is ASCII for "m".
#define FO 102 // 102 is ASCII for "f".
#define OO 101 // 101 is ASCII for "e" and denotes an error.
int main() // Main part of program.
{
int i, j; // Counter integer assignment.
int n = 100; // assignment of integer for the number of strings.
char a; // For the m/f (manual or file) option.
char str[100][100]; // Str is the main string to be sorted.
char temp[100]; // Temp is to switch the values for bubble sorting.
a = OO;
i=0;
while(i < 1)
{
printf("To input text manually, press m. To sort a file, press f. \n");
// M/f option.
scanf("%c", &a); // Gets m/f option.
if(a == MO || a == FO) // Checks for valid input.
{
i = 2; // Escape from loop with valid input.
}
if(a != MO && a != FO) // Invalid input.
{
printf("Please insert a valid response. ");
i = 0; // Continue loop until a valid input is reached.
}
}
if(a == MO) // Manual insert option.
{
puts("Enter the number of strings to be sorted.");
scanf("%d", &n); // Gets number of strings.
for(i = 0; i <= n; i++)
{
gets(str[i]); // Gets strings from user.
}
}
if(a == FO) // File option.
{
char b[100]; // File address of text file to be sorted.
FILE * f; // Text file.
printf("Enter file path of file to be sorted.");
scanf("%c", b); // Gets file path.
f = fopen(b, "r"); // Opens file.
fgets(*str, 100, f); // Coverts file into string str.
fclose(f); // Closes file.
}
for(i = 0; i < n; i++) // Begin bubble sort.
{
for(j = i + 1; j <= n; j++)
{
if(strcmp(str[i], str[j]) > 0) // Checks alphabetical value.
{
strcpy(temp, str[i]); // Switch two strings.
strcpy(str[i], str[j]);
strcpy(str[j], temp);
}
}
}
printf("The sorted string:");
for(i = 0; i < n; i++)
{
puts(str[i]); // Prints final output.
}
return 0; // End of main.
}
#include <stdio.h>
int main()
#include <stdio.h>
int main()
{
char msg[31] = {'\0'};
char encrypted[31] = {'\0'};
int key;
printf("Please enter a message under 30 characters: ");
fgets(msg, 31, stdin);
printf("Please enter an encryption key: ");
scanf("%d", &key);
int i = 0;
while (msg[i] && ('a' <= msg[i] <= 'z' || 'A' < msg[i] < 'Z'))
{
encrypted[i] = (msg[i] + key);
i++;
}
printf("%s\n", msg);
printf("%d\n", key);
printf("%s\n", encrypted);
}
Okay i've got my code to increment the characters but i don't know how to make it ignore special characters and spaces. Also how do i use % to loop back to 'a' and 'A'?
Thank you.
You just need a simple for loop:
for (int i = 0; i < 31; i++)
{
// operate on msg[i]
}
If you didn't know the length of the string to begin with, you might prefer a while loop that detects the null terminator:
int i = 0;
while (msg[i])
{
// operate on msg[i]
i++;
}
Your fgets and scanf are probably fine, but personally, I would be consistent when reading input, and fgets for it all. Then you can sscanf to get key out later.
scanf and fgets seem fine in this situation the way you've used them.
In C, a string is just an array of characters. So, you access each element using a for loop and array indexing:
for (int i = 0; i < strlen(str); i++) {
char thisChar = str[i];
//Do the processing for each character
}
You can perform arithmetic on thisChar as necessary, but be careful not to exceed 255. You might want to put a check on key to ensure it doesn't get too big.
Getting a string from scanf:
char msg[31];
scanf("%30s", msg);
OR (less efficient, because you have to fill the array with 0s first)
char msg[31] = { 0 };
scanf("%30c", msg);
Iterating a string is as easy a for loop (be sure to use c99 or c11)
int len = strlen(msg);
for(int i = 0; i < len; i++) {
char current = msg[i];
//do something
msg[i] = current;
}
"Encrypting" (i.e. ciphering) a character require a few steps
Determine if we have an uppercase character, lowercase character, or non-alphabetic character
Determine the position in the alphabet, if alphabetic.
Update the position, using the modulus operator (%)
Correct the position, if alphabetic
I could give you the code here, but then you wouldn't learn anything from doing it yourself. Instead, I encourage you to implement the cipher based on the steps I provided above.
Note that you can do things like:
char c = 'C';
char e = 'E' + 2;
char lower_c = 'C' - 'A' + 'a';
#include <stdio.h>
#include <ctype.h>
/* prototypes for functions */
void getstring(char *sentence);
int check(char *sentence, int missing[26]);
void showNegativeResults(int[]);
int main(void) {
char sentence[1024] = {'\0'};
int missing[26] = {0};
printf("Enter sentence\n(ending with a period like this one).\n\n");
getstring(sentence);
printf("\nSentence: \"%s.\"", sentence);
if ( check(sentence, missing) )
printf("\n\nThe sentence IS a pangram!\n\n");
else
showNegativeResults(missing);
return 0;
}
void getstring(char *sentence) {
int j = 0;
while ((sentence[j] = getchar()) != '.')
j++;
sentence[j] = '\0';
}
int check(char *sentence, int missing[26]) {
return 1; /* return a 1 if it is a pangram*/
return 0; /*return 0 if it is not a pangram */
}
void showNegativeResults(int missing[26]) {
int c;
printf("\n\nThe sentence is NOT a pangram.\n");
printf("Missing letters:");
for(c = 0; c < 26; c++)
if (missing[c])
printf(" %c", ('a' + c));
printf("\n\n");
}
I need help implementing a function that will decipher whether the characters in the string contain all the letters of the alphabet and if they don't allow the user to know which ones are missing.
Have you been taught about invariants? I suggest you look for an invariant that generalizes these two special cases:
If you have not looked at any part of the sentence, you must consider that all letters are missing.
If you have looked at all of the sentence, then as you have written, the missing data structure contains exactly those letters that are missing from the sentence.
I also suggest you look up the ANSI C functions isalpha and tolower.
An answer without doing your homework ...
1) get the character
2) is it a "."
a) check if you have all and return result.
b) continue
3) is it greater than/equal "A" but less than/equal "Z" ( this defines a range of characters )
a) add it to list return to (1)
b) continue
4) is it greater than/equal "a" but less than/equal "z" ( another range, could be combined with the first )
a) add it to list return to (1)
b) continue
5) is it a " " ( a space .. but could be another range, could be combined with the first )
a) continue
6) error not a correct character and exit
Inside check, you can iterate through the string sentence and for each character you encounter, change missing to 1 for that character.
At the end, the missing characters will be marked with 0. If missing contains at least a 0, you return 0, otherwise 1.
I'm not going to write the full code, but some hints to get you started:
1) You can mark the correct element using currentCharacter - 'a'. This will return you the index of character currentCharacter.
2) You can iterate through the string using
char currentCharacter;
while( currentCharacter = *(sentence++) )
{
//mark array here
}
Just iterate through the input string marking which characters are in it, then check the ones that are missing:
int main()
{
char str[] = "Some meaningful text";
int freq[256];
int i;
for ( i = 0; i < 256; i ++) // clear frequency array
{
freq[i] = 0;
}
for (i = 0; str[i] != '\0'; i++) // parse input string
{
freq[str[i]]++;
}
for ( i = 0; i < 256; i ++)
{
if (freq[i]==0 && isalpha(i)) // find out which leters weren't typed
{
printf("%c letter wasn't typed!\n", (char)i);
}
}
return 0;
}
The simplest way I can think of going about this would be to loop through each letter of the alphabet and check if the letter is in the sentence(by looping through the sentence until the letter was found or you reach the end of the sentence). If the letter is not in the sentence, add the number (corresponding to the missing letter) to your array.
here's the working function:
int check(char *sentence, int missing[26])
{
int missIndex = 0; //the index for the missing array;
bool iWasFound; //was the letter found? (used in the loops below)
for(char i = 'A'; i <= 'Z'; i++)
{
iWasFound = false;
for(int j = 0; j < 1024; j++)
{
if(toupper(sentence[j]) == i)
{
iWasFound = true;
break;
}
}
//if we did not find the letter, add the corresponding number to the missing array
if(!iWasFound)
{
missing[missIndex] = (int)(i - 'A');
cout << (int)(i - 'A') << " | " << missing[missIndex] << std::endl;
missIndex++;
}
}
if(missing[0] == -1)
{
return 1;
}
else
{
return 0;
}
}
let me know if you need me to explain anything