CS50 Caesar output comes as aaaaa - arrays

For some reason when I change the copy of string s that is (string c), string s also gets changed and for loop j keeps on looping until it reached position zero in string alphabet which is 'a'.
int key = atoi(keys);
string s = get_string("plaintext: ");
string c = s;
int length = strlen(s);
string alphabet = "abcdefghijklmnopqrstuvwxyz";
string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int position = 0;
for (int i = 0; i < length; i++)
{
printf("Before Conversion: %c\n",s[i]);
for (int j = 0; j < 26; j++)
{
if(s[i] == alphabet[j])
{
position = (j + key) % 26;
c[i] = alphabet[position];
printf("Ascii: %i + Key: %i.. Position = %i\n",j,key,position);
position = 0;
printf("Not Converted: %c\n",s[i]);
printf("After conversion: %c\n\n",c[i]);
}
if(s[i] == ALPHABET[j])
{
position = (j + key) % 26;
c[i] = ALPHABET[position];
printf("Ascii: %i + Key: %i.. Position = %i\n",j,key,position);
position = 0;
printf("After conversion: %c\n\n",c[i]);
}
}
}
printf("ciphertext: %s\n",c);

Change:
string s = get_string("plaintext: ");
string c = s;
to
string s = get_string("plaintext: ");
string c = malloc(strlen(s) + 1);
strcpy(c, s);
That will make it work. The biggest problem here is that the course CS50 is using
typedef char* string;
to hide the complexity of pointers for new students, but in reality it just causes confusion. In order to fully understand why the above solution works, you need to understand pointers and dynamic allocation.

Related

Function to filter non digit characters in a string

So I'm currently trying to create a function to filter out non digit characters but I can only use strlen. For example, "a4n55" -> "455" I've attempted it and I feel like I'm close. The printf's are just for testing.
void filterNonDigitCharacters(char inData[], char outData[])
{
// create variables
int stringLen, i, j;
// get string length
stringLen = strlen(inData);
printf("Before filter: %s\n", inData);
// loop across string
for(i = 0; i < stringLen; i++)
{
// check if char is a number
if(inData[i] >= '0' && inData[i] <= '9')
{
outData[i] = inData[i];
printf("Filtering number: %c at location: %d\n", outData[i] , i);
}
// check if char is a letter
else if(inData[i] >= 'a' && inData[i] <= 'z')
{
j = i;
printf("Letter found : %c at index: %d\n", inData[i], i);
outData[j] = inData[i + 1];
printf("Moving number down: %c\n", outData[j]);
}
}
outData[i] = inData[i];
printf("New String: %s\n", outData);
}
There is no need to do anything in the event a character is not a digit. Simply maintain a separate index for the output, and increment it only when a digit is found.
Remember to null-terminate the result.
void filterNonDigitCharacters(char inData[], char outData[])
{
size_t j = 0;
size_t length = strlen(inData);
for (size_t i = 0; i < length; i++)
{
if (inData[i] >= '0' && inData[i] <= '9')
{
outData[j++] = inData[i];
}
}
outData[j] = 0;
}
Consider the use of <ctype.h> functions such as isdigit for determining character classes.

Last word in reverse word function

i have this reverse word function. it simply adding word to new string in reverse order . the problem with this code is it not print the last word ( first word before reverse ) . i dont know why . please help fix my code
char str[100], revstr[100];
int i, j, index, len, startIndex, endIndex;
printf("\n Please Enter any String : ");
gets(str);
len = strlen(str);
index = 0;
endIndex = len - 1;
printf("\n ***** Given String in Reverse Order ***** \n");
for(i = len - 1; i > 0; i--)
{
if(str[i] == ' ')
{
startIndex = i + 1;
for(j = startIndex; j <= endIndex; j++)
{
revstr[index] = str[j];
index++;
}
revstr[index++] = ' ';
endIndex = i - 1;
}
}
printf("\n Given String in Reverse Order = %s", revstr);
return 0;
Here's a working code:
char str[100], revstr[100];
int i, j, index, len, startIndex, endIndex;
printf("\n Please Enter any String : ");
gets(str);
len = strlen(str);
index = 0;
endIndex = len - 1;
printf("\n ***** Given String in Reverse Order ***** \n");
for(i = len - 1; i >= -1; i--)
{
if(i == -1){
startIndex = i + 1;
for(j = startIndex; j <= endIndex; j++)
{
revstr[index] = str[j];
index++;
}
revstr[index++] = ' ';
endIndex = i - 1;
break;
}
if(str[i] == ' ')
{
startIndex = i + 1;
for(j = startIndex; j <= endIndex; j++)
{
revstr[index] = str[j];
index++;
}
revstr[index++] = ' ';
endIndex = i - 1;
}
}
printf("\n Given String in Reverse Order = %s", revstr);
The problem was that you were only including a word if there was a space before it. There will be no space before the first word therefore I made the code go before the first letter and always include the first word forcefully. This code can be broken if there are more spaces than needed in the text.

Array not giving back letters the user entered

int read_word(char word[], int max_size_word) {
{
int c = 0, let_count = 0;
printf("\nPlease enter your word: ");
char input = toupper(getchar());
for(c = 1; c < 7; c++) {
if(input != '\n') {
word[c] = input;
let_count++;
} else if(input == '\n')
input = toupper(getchar()); //The word the user entered is in word[c]
}
return let_count;
}
}
int check_word(char word[], int size_word, int letter_set[], int
size_letter_set, int arr[])
{
char word_copy;
for(int ii = 0; ii < 7; ii++) {
word_copy = word[ii];
}
printf("The word is %c\n" , word_copy);
return 0;
}
I'm programming a game of scrabble. Here are the two functions that pertain to my question. Basically I want to check if my read word function works. Thats what the bottom printf does. However when I enter a couple letters my "The word is...." printf only gives back the first letter entered. I want the printf to give back every letter entered. Any help would be appreciated!
You're only printing one letter because in printf("The word is %c\n" , word_copy); your word_copy is a char and not a string.
In check_word, try replacing
char word_copy;
for(int ii = 0; ii < 7; ii++) {
word_copy = word[ii];
}
printf("The word is %c\n" , word_copy);
return 0;
by
int word_size = strlen(word); //calculate the length of your word
char word_copy[word_size + 1]; //create copy string with word size +1 for \0
int ii = 0;
for(ii; ii < 7; ii++) { //I set ii < 7 to do like you but... Why did you set 7?
word_copy[ii] = word[ii]; //put the characters of your word into the copy string
}
word_copy[ii] = '\0'; //end the string puttin a \0 at its end
printf("The word is %s\n" , word_copy); //here i replace %c (char) by %s (string)
return 0;
There are similar problems in your read_word function, you should be able to fix them if you understand the fixes I made in your check_word function (even if you can just put your printf in the for loop i think that doing it like so can help you understand the problem in read_word).

C program to find substring in string

So I may be attacking this the wrong way; I was learning a bit of Javascript and wrote a program that will find a string contained in another string and store the matches in an array (sorry if that didn't make too much sense, seeing my C program should help). I tried to translate my program to C, but it doesn't work; I think my issue is data types:
int main () {
char text[58];
strcpy(text, "I am James, James the Great, a pretty cool guy named James");
char store[16];
char name[6] = "James";
for (int i = 0; i <= 16; i++) {
if (text[i] == 'J') {
for (int k = i; k < i + 6; k++) {
store[k] = text[i];
}
}
}
int a = sizeof(store) / sizeof(store[0]);
for (int b = 0; b < a; b++) {
/* This should print out the values stored in the store array */
printf("%d", store[b]);
}
return 0;
}
My expected result would be something like:
JamesJamesJames
Instead I get:
10000747474747474-6374747474
So I'm assuming it's doing exactly what I told it to do, just not storing the letters into the array as letters, a bit confusing. Is there a better way to do this?
This is the javascript code I was trying to translate:
var text = "I am James, James the Great, a pretty cool guy named James";
var myName = "James";
var hits =[];
for (i = 0; i < text.length; i++) {
if (text[i] === "J") {
for (var j = i; j < i + myName.length ; j++) {
hits.push(text[j]);
}
}
}
if (hits.length === 0) {
console.log("Your name wasn't found!");
} else{
console.log(hits);
}
You are going to break store[] with this line
for (int k = i; k < i + 6; k++) {
because you are writing to the same index as you found the text in text[]. You also loop one too many times (6)
int ind = 0;
for (int k = 0; k < 5; k++) {
store[ind++] = text[i+k];
}
Then your next statement doesn't tell you anything about the data you collected
int a = sizeof(store) / sizeof(store[0]);
Just remove it, and print ind characters from store[].
You made following mistakes.
for (int i = 0; i <= 16; i++)
You iterate by '16' but this isn't proper length of text.
for (int k = i; k < i + 6; k++)
So you iterate by "i, i+1, i+2, i+3, i+4, i+5, i+6" here is 7 chars, "James" have 6.
store[k] = text[i];
You aren't changing "i" value so text[i] always return 'J'. It's better to use savePoistion variable so do I in the following code.
int a = sizeof(store) / sizeof(store[0]);
for (int b = 0; b < a; b++) {
/* This should print out the values stored in the store array */
printf("%d", store[b]);
}
I have no idea what are you trying to do here. It's really unnecessary.
printf("%d", store[b]);
"%d" means that you are printing integers so don't be surprised that your output was numbers. Just simply printf("%s\n", store);
This should look like this
int main () {
char text[58];
strcpy(text, "I am James, James the Great, a pretty cool guy named James");
char store[20];
int len = strlen(text);
int savePosition = 0;
int i, k;
for (i = 0; i < len; i++) {
if (text[i] == 'J') {
for ( k = i; k < i + 5; k++) {
store[savePosition] = text[k];
++savePosition;
}
}
}
store[savePosition] = '\0';
printf("%s\n", store);
return 0;
}
int main (void) {
char text[] = "I am James, James the Great, a pretty cool guy named James";
char name[] = "James";
char store[16] = {0};
int store_index = 0;
for (int i = 0; i < strlen(text); i++) {
if (text[i] == 'J') {
for (int k = i; k < i + strlen(name); k++) {
store[store_index++] = text[k];
}
}
}
if(strlen(store)==0) {
printf("Your name wasn't found!\n");
} else {
printf("%s\n", store);
}
return 0;
}
rewrite version.
int main (void) {
char text[] = "I am James, James the Great, a pretty cool guy named James";
char name[] = "James";
char store[sizeof(text)];
char *p = strstr(text, name);
if(p == NULL) {
printf("Your name wasn't found!\n");
} else {
int len = strlen(name);
int index = 0;
do {
memcpy(store + index, name, len);
index += len;
p = strstr(p + len, name);
} while(p != NULL);
store[index] = 0;
printf("%s\n", store);
}
return 0;
}

Displaying wrong character in C

I'm testing deciphering strings using a key in standard C. I'm inputting a string, inputting my replacements and constructing a cipher based on the history of my replacements. For example, if I replace c with h in a string, I will store it in the string cipher as "ch ", where " denotes the start and end of my string.
My problem is, as I'm trying to run back through my string and revert characters back to their originals, my characters are messing up and showing as heart signs instead. Any insight on this would be much appreciated, I'm sure I'm going wrong somewhere very simple.
char from[] = "";
char to[] = "";
for (int i = 0; i <= strlen(cipher); i++){
if (i == 0){
from[strlen(from)] = cipher[i];
}
else if(cipher[i-1] == ' '){
from[strlen(from)] = cipher[i];
}
else{
to[strlen(to)] = cipher[i];
}
}
for (int i = 0; i <= strlen(str); i++){
for(int j = 0; j <= strlen(to); j++){
if(str[i] == to[j]){
str[i] = from[j];
}
}
}
printf("\nUNSCRAMBLED STRING IS: %s" ,str);
cipher is the char array holding my cipher key. to[] hold the second value in the cipher key. from[] holds my first. str is the char array of the string that is to be deciphered.
You have a number of problems.
(1) One big problem is that you don't have enough storage allocated for from and to - change:
char from[] = ""; // this is equivalent to char from[1] = "";
char to[] = "";
to e.g.:
char from[256] = "";
char to[256] = "";
(where 256 is just some arbitrary size that should be greater than the size of your data set).
(2) You need to terminate your strings properly when you append a character, e.g.
if (i == 0){
from[strlen(from)] = cipher[i];
}
should be:
if (i == 0){
int len = strlen(from);
from[len] = cipher[i];
from[len + 1] = '\0';
}
(3) You're indexing by one too many characters when you iterate through a string, so e.g.
for (int i = 0; i <= strlen(cipher); i++){
should be:
for (int i = 0; i < strlen(cipher); i++){

Resources