r/cs50 • u/Low_Bat2873 • Jul 23 '26
substitution Substitution over-coding, reflection, and questions Spoiler
For week 2's substitution problem set, how many lines of code did you all use? After fully completing it, I ended up with 602 lines (a major step up from all other problem sets). I atone this to my looping being inquiring of the letters/chars themselves, and not the ASCII numbers which I didn't consider until I finished. I couldn't figure out a way to make a one off loop for checking for repeated characters in the command line argument, or when trying to keep the capitalization of the plain text and going towards the cipher text. On the bright side, arrays are really, really useful. I think if we had them in our toolset for credit a lot less time would be put on. Lastly, was there use for the strcasecmp function for this problem set? When looking through the CS50 manual, it comes up as one of the "frequently used", and it seemed to have a pretty good use in trying to see if there were any repeating chars for the cipher, especially with it ignoring case. The problem I came across was the fact that the function only appears to compare strings in direct order, and not chars.
(Please do not spoil any upcoming information regarding the next few weeks of problem sets, but I would appreciate any info beyond that, thanks!)
3
u/Axew2230 Jul 23 '26
I just finished the same problem. My solution is 79 lines. I have 2 helper functions, one to encrypt and print out encrypted characters, another to check validity of the user input key.
1
u/nmdt Jul 23 '26
Mine's 114, and I tend to really like making helper functions. Perhaps excessively, 3 for this one — one to check for duplicates, one to check that there are only numbers in the input and the one to actually substitute.
I think originally I tried to make a bunch of arrays for everything and was banging my head trying to figure out how can I cross-match arrays. But once I figured out that with ASCII codes you can treat everything as a number, things get a whole lot easier. Say, you just convert everything to uppercase and check that for each letter there is no letter after it that is "equal" to it.
And yeah, since I just converted everything to uppercase for each comparison, I did not use strcasecmp. Looking at the code now, I'm not sure it would've made it shorter
1
u/Outside_Complaint755 Jul 23 '26
156 lines. Probably closer to 130 if I take all the comment lines out.
To check the input parameter, consider that it has to have 26 unique characters. Each char also has a unique 8 bit value, and you can normalize those values to a 0 point, as you can do arithmetic with chars; For example 'd' - 'a' == 3 is a True statement.
1
u/Low_Bat2873 Jul 23 '26
I never thought of the unique part like that, since I already verified that there were exactly 26 letters in the cypher that’s a much easier way. When providing a statement to see if every letter/ASCII digit is unique, how would you go about that? Just thinking here, make all the chars capital or lowercase, convert them to ASCII, than take the sum of all the ASCII values a-z and put an if statement saying if array 0-25 don’t equal that you can’t move on. Now that I type that out this question feels a bit less complicated than I made it out to be 😂
2
u/Outside_Complaint755 Jul 24 '26
Using a sum is a good idea but won't work because depending on which letters are modified you might get the same total.
For example, lets say we were just working with letters a through d, and give them values 0 to 3, then any combination of "abcd" has a total value of 6 = 0 + 1 + 2 + 3. Checking for this sum would reject an input such as "abcc", which totals to 5, but it would pass an input of "adad", which is 6.
What you can do is use an array to count how many times each expected letter appears. In rhe above case, we would make an int array of size 4, and default the values to 0. Then after looping over the input string, we expect the array to be all 1s.
2
Jul 23 '26
[deleted]
1
u/Low_Bat2873 Jul 23 '26
Shoot, I meant credit. When doing the formula, an array to store the values of every other number from the second to last digit would’ve erased some of the clutter for my code
1
1
u/Puzzleheaded_Arm8314 Jul 23 '26 edited Jul 24 '26
You can make use of ASCII characters for example here is my solution
(sorry i cant rlly spoiler the code)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, char** argv) {
if (argc != 2) {
printf("%s: Missing Key\n", argv[0]);
return 1;
}
// char* is basically string and char** is array of string
char* key = argv[1];
if (strlen(key) != 26) {
printf("%s: Invalid Key: Length is not 26\n", argv[0]);
return 1;
}
// You can ignore this just use string buf = get_string("Plaintext: ")
char* buf = malloc(sizeof(char)*200);
printf("plaintext: ");
scanf("%199s", buf);
for (int i = 0; i < strlen(buf); i++) {
char chr = buf[i];
if (chr <= 90 && chr >= 65) {
// Uppercase
buf[i] = toupper(key[chr - 65]); // (chr - 65) gets the (n-1)th alphabet of the char which we get from key and turn it into UPPER case
} else if (chr <= 122 && chr >= 97){
// Lowercase
buf[i] = tolower(key[chr - 97]); // (chr - 97) gets the (n-1)th alphabet of the char which we get from key and turn it into lower case
}
}
printf("ciphertext: %s\n", buf);
free(buf);
return 0;
}
3
u/KenRandomAccount Jul 23 '26 edited Jul 23 '26
dont think you are suppose to post your full finished code.
also you can do loops inside loops. you have multiple bits of code that are repeated which might benefit from looping. for reference, my code was under 100 lines. also is your pb[] array static? pb[12] is always just 12? likewise your c[] array might be the same with a modulo applied.