Python False Concatenate Error? - concatenation

I can't seem to find my mistake. I'm trying to write a simple program that encrypts messages using the caesar shift method. However, I'm getting a funky error. Program is as follows:
alphabet = {"a":0,"b":1,"c":2,"d":3,"e":4,"f":5,"g":6,"h":7,"i":8,"j":9,"k":10,"l":11,"m":12,"n":13,"o":14,"p":15,"q":16,"r":17,"s":18,"t":19,"u":20,"v":21,"w":22,"x":23,"y":24,"z":25}
alpha2 = dict (zip(alphabet.values(),alphabet.keys()))
def key(n):
code = alphabet
for i in code:
code[i] = (code[i] + n) % 26
for i in code:
code[i] = alpha2[code[i]]
return code
def encode(x,n):
my_key = key(n)
message = []
for i in x:
message.append(my_key[i])
print key(13)
print encode("Message",13)
I find this absurd, because after running my ./caesars.py the command line will return
{'a': 'n', 'c': 'p', 'b': 'o', 'e': 'r', 'd': 'q', 'g': 't', 'f': 's', 'i': 'v', 'h': 'u', 'k': 'x', 'j': 'w', 'm': 'z', 'l': 'y', 'o': 'b', 'n': 'a', 'q': 'd', 'p': 'c', 's': 'f', 'r': 'e', 'u': 'h', 't': 'g', 'w': 'j', 'v': 'i', 'y': 'l', 'x': 'k', 'z': 'm'}
Traceback (most recent call last):
File "./caesars.py", line 56, in <module>
print encode("Message",13)
File "./caesars.py", line 27, in encode
my_key = key(n)
File "./caesars.py", line 15, in key
code[i] = (code[i] + n) % 26
TypeError: cannot concatenate 'str' and 'int' objects
Which clearly means that the first run through of the key function was successful, but when the encode functions tries to call the key function a second time it decides to have issues? I have printed the types of n, and they come out as int. I'm sure this is an oversight in my code, but for the life of me I can't find it.

You probably expected
code = alphabet
to copy the alphabet dict into code. That's not what happens. This line evaluates the alphabet variable, producing a reference to a dict, and then makes code refer to that same dict. Setting items of code will also change alphabet, because both variables are names for the same dict. In particular, after
for i in code:
code[i] = alpha2[code[i]]
all the values of alphabet are strings.
If you want a copy, you can make a copy:
code = alphabet.copy()
though a copy of alphabet might not be the cleanest starting point to construct code.

Related

If function and scanf function not working together

so I have been trying to write a code that displays different messages if different keys are pressed
It should display "Your hair looks nice" if one of the characters of the string is pressed and display "You look like your mom" if any number of symbol is pessedd (anything other than the array's elements)
what is the issue here?
(Mind the messages in the code I'm trying to stay chill so I picked random messages)
the code:
#include<stdio.h>
int
main ()
{
char i,o;
char a[54] =
{ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'g', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C',
'D',
'E', 'F', 'G', 'H', 'I', 'G', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T',
'U', 'V', 'W', 'X', 'Y', 'Z'
};
if (scanf ("%c", &o) == a[i])
printf ("Your hair looks nice");
else
printf ("You look like your mom");
return 0;
}
C have a set of standard character classification functions, like for example isalpha to check if a character is a letter or not.
With this you can make your program much simpler, and don't need the array:
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int ch = getc(); // Read one character
if (isalpha(c))
{
puts("Your hair looks nice.");
}
else
{
puts("You look like your mom!");
}
}
Note that I use the getc function to read a character instead. In most cases scanf shouldn't really be used for input, it's use is unfortunately more non-trivial than the beginners guides and tutorials make it seem.
You need to check all relevant values of i. Currently, you don't even assign a single value to i, but you need to assign 54 different values in turn.
And of course, you need to call scanf only once, not 54 times.
If you want to see whether the inputted character is in the array, then you must compare that character with all 54 characters in the array. However, in your posted code, you are only making one comparison. I suggest that you use a for loop for doing the 54 comparisons. You can do one comparison per loop iteration.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
char a[54] = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'g', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'G', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
};
char input;
//get input character
if ( scanf( "%c", &input ) != 1 )
{
fprintf( stderr, "Input error!\n" );
exit( EXIT_FAILURE );
}
//determine whether input character is in array
for ( int i = 0; i < 54; i++ )
{
if ( a[i] == input )
{
printf( "Found character in array.\n" );
return 0;
}
}
printf( "Did not find character in array.\n" );
return 0;
}
However, in order to determine whether a character is an alphabetical letter, there is a much simpler solution: You can simply call the function isalpha as demonstrated in one of the other answers.
From scanf's man page:
RETURN VALUE:
On success, these functions return the number of input items successfully matched and assigned; this can be fewer than provided for, or even zero, in the event of an early matching failure.
According to this, the statement
if (scanf ("%c", &o) == a[i])
compares the return value of scanf, which in this case would be one 1(if scanf succeeded) to a[i], where i is uninitialised and leads to undefined behaviour. As I remember #Fe203 once saying:
"Leaving variables uninitialised is asking Demon of Hard-To-Find Bugs to co-author your code."
So you ought to first initialise i, then iterate through the array, comparing o to all the 54 values of i.
Aside:
You shouldn't be using scanf for user-interactive stuff. It is not supposed to be used as such, and it's quite hard to get right. In this case, consider using getc or getchar which reads one character at a time.
Or at least, check the return value of scanf.

Encrypt a string according to the table

I have a problem. For example there is a table like this: table
and want to enter a string for instance like str[] = "şğüö 1234?!" and the program will print the the code like 2422545376354555655666.
It is a encryption question. I created a two dimensional array like this:
char signs[7][6] = {{'A', 'G', 'L', 'S', 'Z', '6'},
{'B', 'Ğ', 'M', 'Ş', '0', '7'},
{'C', 'H', 'N', 'T', '1', '8'},
{'Ç', 'I', 'O', 'U', '2', '9'},
{'D', 'İ', 'Ö', 'Ü', '3', '?'},
{'E', 'J', 'P', 'V', '4', '!'},
{'F', 'K', 'R', 'Y', '5', ' '}};
And I thought that I could search the string's letters in this two-dimensional array. When the program find the letter, it can print the values of i and j. (Nested loops' elements)
Do you have another solution for that question? I really need your help. Because I cannot do that.
It appears you are using an 8bit "character code" table.
Rather than doing a "look-up" search through this table of yours, you could simply print the character translated to 2 hexadecimal values:
for( int i = 0; str[i]; i++ )
printf( "%02X", (unsigned char)str[i] );
If you think that 'hex' would be too obvious, you could go for 3 digit octal instead:
printf( "%03o", (unsigned char)str[i] );
There are myriad 'simple' encryption schemes that would defeat most casual observers.
Then, you must consider the 'decryption' complement to whatever scheme you choose.

Char array null termination & length in c

I am writing a function to check length of a char array in c. It takes another parameter, which sets the limit for \0 check.
int string_length(char* string, int maximum_length) {
int i = 0;
while(string[i] != '\0' && i < maximum_length) {
i++;
}
return i;
}
In this answer, it is mentioned that a char array must be null terminated, if it is created using {} syntax. I call the above function with not terminated char array & the result is 10(9 letters + 1).
char not_terminated_string[] = {'m', 'y', ' ', 's', 't', 'r', 'i', 'n', 'g' };
int length = string_length(not_terminated_string, 100);
// length is 10
I am not able to understand why is it this way.
For the following line, C compiler creates an array of 10 char size elements and lays down the first 9 characters, adding a string \0 delimiter at the very end.
char *a = "my string";
Considering the following line; C compiler creates an array of 9 char size elements and lays down the characters. A string delimiter is not added at the very end. If there happens to be a zero value at the 10th byte (byte number 9), that would be only by chance.
char b[] = { 'm', 'y', ' ', 's', 't', 'r', 'i', 'n', 'g' };
The statement "a char array must be null terminated, if it is created using {}" means, if you want to be able to use that char array as a string (like, to be able to use it in a printf), then you should add a string terminating character by yourself, like;
char b[] = { 'm', 'y', ' ', 's', 't', 'r', 'i', 'n', 'g', '\0' };
Your program produced ten because you defined an array of only nine non-null characters, but it happened to be followed by one more non-null character and then a null character. (Technically, the behavior of your program is not defined by the C standard due to overrunning the array, and there are other ways your program could then have misbehaved to produce ten, but this is the most likely occurrence.)
The declaration char not_terminated_string[] = {'m', 'y', ' ', 's', 't', 'r', 'i', 'n', 'g' }; defines not_terminated_string to be an array of nine char, which are initialized with the given characters. No null character is automatically appended to this array.
When your program passed this array to string_length, that routine counted the nine characters in the array, and then it attempted to look at the tenth. It appears, most likely, that the next byte in memory was not null, so the routine counted it and looked at the eleventh. It appears that one was null, so the routine stopped and returned ten.

Program to bubble sort a txt file in C

I'm writing a C program to be given a txt file containing names of player and how many wins they have (its for a bigger game project), and sort them from highest to lowest amount of wins. While the code compiles and successfully orders the wins im experiencing a problem with the names where they seem to be stacking on top each other.
#include<stdio.h>
#include<stdlib.h>
char name[20];
int wins[20];
void main()
{
FILE *fp;
int i=0,size,j,swap;
char ch;
fp=fopen("record.txt","r");
if(fp==NULL)
{
printf("\n Cannot open the file \n");
exit(0);
}
while(ch!=EOF)
{
fscanf(fp,"%s %d",&name[i],&wins[i]);
ch=fgetc(fp);
i++;
}
size=i-1;
for(i=1;i<size;++i)
for(j=0;j<size-i;j++)
if(wins[j+1]>wins[j])
{
swap = wins[j];
wins[j] = wins[j+1];
wins[j+1] = swap;
swap = name[j];
name[j] = name[j+1];
name[j+1] = swap;
}
fp=fopen("sortedRecord.txt","w");
for(i=0;i<size;i++){
fprintf(fp,"%s %d \n",&name[i],wins[i]);
printf ("%s %d \n", &name[i],wins[i]);
}
fclose(fp);
}
Here is the input file "record.txt"
Andrew 5
Billboy 10
Hill 7
Mill 1
And here is what i get when i run it.
BHAMill 10
HAMill 7
AMill 5
Mill 1
I'm new to code so i know mine sucks but for the life of me i cant see exactly where its going wrong. Any help or advice is appreciated.
As jwdonahue said the issue is with your definition of name. char name[20] creates an array of 20 chars, not 20 strings.
When you run the while(ch!=EOF) loop what's happening? First time through you find the address of the 0th element in name and write Andrew there so name has ['A', 'n', 'd', 'r', 'e', 'w', '\0', '\0', '\0', '\0'] (the \0 is the end of string character). Second time through you find the address of the 1st element in name and write Billboy, but the 0th element is still there and hasn't changed so you end up with the contents being ['A', 'B', 'i', 'l', 'l', 'b', 'o', 'y', '\0', '\0']. Adding Hill to the 2nd position results in ['A', 'B', 'H', 'i', 'l', 'l', '\0', 'y', '\0', '\0']. Then finally adding Mill gives the array ['A', 'B', 'H', 'M', 'i', 'l', 'l', '\0', '\0', '\0'].
When you then go to sort scores you are sorting the characters in this array which end up as ['B', 'H', 'A', 'M', 'i', 'l', 'l', '\0', '\0', '\0'] (only the first four characters will be affected by your sort). In your print statement you then print the character array starting at the 0th, 1st, 2nd and 3rd positions respectively so you get BHAMill, HAMill, AMill, and Mill.
Hopefully that should help you enough to get you unstuck. :)

C: Base 64 to binary conversion

I've been working to implement a base64 decoder in C. I have been reading up on base64 conversion in places such as the Wikipedia page and also using online converters to check my work. It seems straight forward: just replace every base64 character with the corresponding 6-bit binary string!
My Base64-to-binary decoding is correct as long as the base64 string to decode is a multiple of 4. If the string length is not a multiple of 4, or there are equal signs present for padding, my code does not match the results from online converters.
I thought I understood the padding -- just replace the '=' character with zeros (6, for 6 bits). However, I still don't match the converter's result when this is employed.
Here is the code I've written:
int main(void){
printf("Testing b642bin ...\n\n");
printf("Case 1: Converting 'AA==' to bin:\n");
printf("Expected Result: 000000000000000000000000\n");
printf("Actual Result: %s\n\n", b642bin("AA=="));
printf("Case 2: Converting '+aHg' to bin:\n");
printf("Expected Result: 111110011010000111100000\n");
printf("Actual Result: %s\n\n", b642bin("+aHg"));
printf("Case 3: Converting 'kNSHd94m7d+=' to bin:\n");
printf("Expected Result: 1001000011010100100001110111011111011110001001101110110111011111\n");
printf("Actual Result: %s\n\n", b642bin("kNSHd94m7d+="));
return 0;
}
char bin6_table[65][7] = {"000000", "000001", "000010", "000011", "000100",
"000101","000110", "000111", "001000", "001001",
"001010", "001011", "001100", "001101", "001110",
"001111", "010000", "010001", "010010", "010011",
"010100", "010101", "010110", "010111", "011000",
"011001", "011010", "011011", "011100", "011101",
"011110", "011111", "100000", "100001", "100010",
"100011", "100100", "100101", "100110", "100111",
"101000", "101001", "101010", "101011", "101100",
"101101", "101110", "101111", "110000", "110001",
"110010", "110011", "110100", "110101", "110110",
"110111", "111000", "111001", "111010", "111011",
"111100", "111101", "111110", "111111", "000000"};
char base64_table[65] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/','='};
char* b64Char2bin(char b64){
int n = 64;
int k;
char *bin;
for(k=0;k<n;k++){
if (b64 == base64_table[k]) {
bin = bin6_table[k];
break;
}
}
return bin;
}
char* b642bin(char *b64_str) {
int i;
size_t len = strlen(b64_str);
char* bin_str = (char*)malloc(((len * 6) + 1) * sizeof(char));
for (i = 0; i < (int)len; i++) {
const char* binSextet = b64Char2bin(b64_str[i]);
memcpy(&bin_str[6*i], binSextet,7);
}
return bin_str;
}
The output looks like this:
Testing b642bin ...
Case 1: Converting 'AA==' to bin:
Expected Result: 000000000000000000000000
Actual Result: 000000000000000000000000
Case 2: Converting '+aHg' to bin:
Expected Result: 111110011010000111100000
Actual Result: 111110011010000111100000
Case 3: Converting 'kNSHd94m7d+=' to bin:
Expected Result: 1001000011010100100001110111011111011110001001101110110111011111
Actual Result: 100100001101010010000111011101111101111000100110111011011101111110000000
If the converter I provided is correct, I don't understand Base64. Clearly you do not simply replace each character with the corresponding 6 bits of binary. Why is Case 1 and 2 correct, but Case 3 is not?
Bytes (well, octets if you want to get all technical) are 8 bits long. Base64 encodes 6 bits at a time. Padding is used when the number of bytes that were encoded isn't a multiple of three, therefore the number of bits isn't a multiple of six. When decoding base64 with padding, you don't output more zero bits, you output less bits to produce the correct number of bytes.
As a concrete example:
Base64: ////
Binary: 11111111 11111111 11111111
Base64: //8=
Binary: 11111111 11111111
Base64: /w==
Binary: 11111111

Resources