I was solving a codewars problem called "decoding a message" using C.
My code passed the sample tests but can't pass the random tests as it adds random chars after the required chars like in the image enter image description here
What's the problem here?
problem's link : [https://www.codewars.com/kata/565b9d6f8139573819000056]
#include <string.h>
#include <ctype.h>
char *decode (const char *encoded, char *decoded)
{
for (int i = 0; i < strlen(encoded); i++)
{
if (isalpha(encoded[i]))
{
if (encoded[i] <= 109)
{
decoded[i] = encoded[i] + 25 - ((encoded[i] - 'a')*2);
}
else if (encoded[i] >= 110)
{
decoded[i] = encoded[i] - 25 + (('z' - encoded[i])*2);
}
}
else
{
decoded[i] = encoded[i];
}
}
return decoded; // return it
}
As indicated in the comments, the symptom described by the OP suggests the receiving buffer is not terminated properly to make a C string.
Further, one should avoid using "magic numbers" like 109 and 110 in code... What do those numbers mean?? They certainly won't work if the constraint of being "all lowercase" is lifted. Would one then copy/paste/adapt many lines of code merely to deal with both upper and lower case alphabets?
Below is LESS code that not only deals with the OP problem (unterminated string) but also deals with both upper and lower case letters (recognising that 'case' would weaken any encryption. Included here to demonstrate technique, only.)
Have fun with these learning challenges.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
char *decode( const char *s, char *d ) {
for( size_t i = 0; ( d[i] = s[i] ) != '\0'; i++ ) { // copy every byte
if( isalpha( d[i] ) ) { // transform needed ?
char c = islower( d[i] ) ? 'a' : 'A'; // basis to transpose ASCII char to 0-25
d[i] = (char)( c + ( 25 - ( d[i] - c ) ) ); // 0->25 ==> 25->0
}
}
return d; // return it
}
int main() {
char *hidden = "R slkv MLYLWB wvxlwvh gsrh nvhhztv";
char buf[ 128 ];
printf( "%s\n%s\n", hidden, decode( hidden, buf ) );
return 0;
}
R slkv MLYLWB wvxlwvh gsrh nvhhztv
I hope NOBODY decodes this message
If any of this is unclear, please post a question below...
Related
I am doing some kind of challenge in C in the internet and got the following mission:
Given a string, that consists of some ascending characters one after the other (by ASCII value), return the same string, but replace the middle letters of the sequence with one minus sign
Example:
Given the following input: dabcefLMNOpQrstuv567zyx
We expect the following output: da-cefL-OpQr-v567zyx
The code I've tried:
/* Importing useful libs */
#include <stdio.h>
#include <string.h>
/* Declaring boolean definitions */
typedef enum {
false,
true
}
bool_enum;
/* Declaring Max. Input Length */
#define MAX_INPUT_LENGTH 80
void sequence_replace(char string[]);
/* Main Function */
int main() {
char input_str[MAX_INPUT_LENGTH];
printf("Please enter the string you'd like to switch its sequences with the three char method: ");
scanf("%s", input_str);
sequence_replace(input_str);
return 0;
}
void sequence_replace(char string[]) {
int first_char, last_char;
int slen = strlen(string);
bool_enum sequence = false;
for(int i = 0; i < slen; i ++) {
int s1 = string[i];
int s2 = string[i+1];
if (s1 + 1 == s2) {
if (sequence = false) {
sequence = true;
first_char = i;
}
}
if (s1 + 1 != s2) {
if (sequence = true) {
last_char = i;
string[first_char + 1] = '-';
for(int j = first_char+2; j < last_char; j++) {
string[j] = '';
}
}
sequence = false;
}
}
printf("Sequences after replacement are: %s", string);
}
Basically what I tried to do, is in the sequence_replace function iterate over the string until I find one character whose ascii code + 1 equals to the ascii code of the next character, I change a boolean flag to true to show that I am inside a sequence as well as keeping the index of when the first character of the sequence showed up, then once it hits a character whose ascii code - 1 is not equal to the previous character ascii code, I then switch the character that comes next after the first character with '-' sign and then just run a loop until the end of the sequence to replace all other remaining chars with just an empty string.
Unfortunately, doesn't seem to be working, Would like to get any help if possible.
For starters there is no need to introduce this typedef declaration
/* Declaring boolean definitions */
typedef enum {
false,
true
}
bool_enum;
It is much better just to include the header <stdbool.h> and use names bool, false and true defined in the header.
The function itself should be declared like
char * sequence_replace(char string[]);
Using the function strlen is redundant and inefficient.
As it follows from the provided example you should check whether a current character is an alpha character or not.
You may not declare integer character constants that do not contain a symbol like this
string[j] = '';
That is in C there are no empty integer character constants.
Also there is a logical error in this if statement (apart from the typo in the inner of statement if (sequence = true) { where there is used the assignment operator = instead of the equality operator ==)
if (s1 + 1 != s2) {
if (sequence = true) {
last_char = i;
string[first_char + 1] = '-';
for(int j = first_char+2; j < last_char; j++) {
string[j] = '';
}
}
sequence = false;
}
It unconditionally write the symbol '-' even if there are only two characters that satisfy the condition
s1 + 1 == s2
In this case according to the provided example the symbol '-' is not inserted.
Also for example the for loop will not process the tail of the string that represents an increased sequence of letters.
The function can look the following way as shown in the demonstration program below.
#include <stdio.h>
#include <ctype.h>
char * sequence_replace( char s[] )
{
char *p = s;
for ( char *q = s; *q; )
{
*p++ = *q++;
char *current = q;
while (isalpha( ( unsigned char )q[-1] ) &&
isalpha( ( unsigned char )q[0] ) &&
( unsigned char )( q[-1] + 1 ) == ( unsigned char )q[0])
{
++q;
}
if (current != q)
{
if (q - current > 1)
{
*p++ = '-';
}
*p++ = q[-1];
}
}
*p = '\0';
return s;
}
int main( void )
{
char s[] = "dabcefLMNOpQrstuv567zyx";
puts( s );
puts( sequence_replace( s ) );
}
The program output is
dabcefLMNOpQrstuv567zyx
da-cefL-OpQr-v567zyx
My code for CS50 pset2 Vigenere cypher is as follows. I am new to C programming.
[ I edited the code once after I got some suggestions and this code(below) is my new edited code.]
When I run the code it produces infinite loop and also new encrypted text is not produced as it is supposed to be. Can I please get some suggestions and advice regarding the correction of my code ?
Thank you,
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, string argv[])
{
if (argc != 2) //if it is not rqual to 2, it gives an error message.
{
printf("Enter the valid input : \n");
return 1;
}
if (argc == 2) //if two commands are given then it proceeds to other step.
{
string k = argv[1];
string m = GetString();
int l = strlen(k);
int p = strlen(m);
for( int i = 0; i <= p ; i++ ) //it has to keep on rotating from 0 to len of string and back to zero and so on.
{
{
i = i % l;
}
if (isalpha(m[i]) && isalpha(k[i])) // it proceeds ahead only if the input given is an alphabet, if the input is sth other than alphabet it prints exactly as it is.
{
for(int t = 0; t <= p ; t++)
{
if(isupper(m[t])) // when is it capital letter.
{
printf("%c", ( m[t] - 65 + k[i]) % 26 + 65);
}
if(islower(m[t])) // when it is small letter.
{
printf("%c" , ( m[t] - 97 + k[i])% 26 + 97);
}
}
}
else //if it is not an alphabet it returns as it is.
{
printf("%c", m[i]);
}
}
}
printf("\n");
return 0;
}
Let's look at the error. It says that the parameter you gave there is not an array, while you are using it as an array. And that's right : p is an integer, and not an array :
int p = strlen(msg);
Using p[i] means that you want to access the element number i of your p array. But it is impossible to reach this value, because p is simply an integer variable, and not an array.
What you probably wanted to use as an array was one of your string parameters, key or msg. A string variable in CS50 is the equivalent of a char * variable in classic C, and is used as an array of characters.
I am trying to run the program assignment caesar.c from the edx Introduction to programming. It requires a program able to encrypt a string with the Caesar encryption: therefore, the user has to enter a key (command-line); for example with a key of 2 a 'A' character needs to be encrypted in a 'C' character; the problem starts when you have to enter a key greater than 26, which is the number of alphabetical letters. For a key of 27 and an 'A' character for example, the program must return 'B' like a key of 1.
I have tried to transform the ASCII values of the characters to alphabetical values from 0 to 26 in order to use the modulus operator when the key is equal or greater than 26.
It returns me a segmentation fault. Can anyone help me with some suggestions of the causes of my error?
Here's the program:
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int key;
// function for an alphabetic value with non capital letters
int alpha_low( char c )
{
int alpha_value;
alpha_value = (int) c - 97;
return alpha_value + ( key % 26 );
}
// function to return to ascii valuee for non capital letters
char ascii_low( char c )
{
return (char) alpha_low( c ) + 97;
}
// function for an alphabetic value with capital letters
int alpha_up( char c )
{
int alpha_value;
alpha_value = (int) c - 65;
return alpha_value + ( key % 26 );
}
// function to return to ascii value for capital letters
char ascii_up( char c )
{
return (char) alpha_up( c ) + 65;
}
int main(int argc, string argv[])
{
int result;
string p;
key = atoi( argv[1] );
if( argc != 2 || key < 0 )
{
printf("Usage: ./caesar key(positive integer)\n");
return 1;
}
printf("Please, write a plaintext: ");
p = GetString();
for( int i = 0, n = strlen(p); i < n; i++)
{
if ( isalpha(p[i]) )
{
if ( islower(p[i]) )
{
result = alpha_low( p[i] );
printf("%c", ascii_low( p[i] ));
}
else if( islower( p[i]) )
{
result = alpha_up( p[i] );
printf("%c", ascii_up( p[i]) );
}
}
}
return 0;
}
A function to caesar an alphabetic char should be like (decomposed in elementary steps):
int caesar_lower(int c,int key) {
int v = c-'a'; // translate 'a'--'z' to 0--25
v = v+key; // translate 0--25 to key--key+25
v = v%26; // translate key--key+25 to key--25,0--key-1
v = v+'a'; // translate back 0--25 to 'a'--'z'
return v;
}
Hey guy's last time I posted I was a bit sloppy. Hopefully this time it'll look a lot better . Thank you for your time if you decide to help me. I really need it. Anyways heres the question. I need to have wrap around for my Code and i heard you can do it with modulus but I am not sure i am doing it correctly because I do not get the right results.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int main () {
char s[200]; //blank array//
int mess;
printf("Generations have wondered how the Ceasar Code works\n");
printf("Please choose a number to mess up (encode) the current file\n");
scanf("%d", &mess);
mess = mess % 26;
FILE *ptof = fopen("Rock.txt", "r");
char a[200];//fill array with characters from file//
int i=0;
while( (a[i++]=fgetc(ptof)) != EOF && i < 89) { //get character from file//
}
a[i] = '\0'; /* null-terminate the string */
i = 0;
do{
printf("%c",a[i++]);
} while (a[i] != '\0'); /* print until hit \0 */
int j = 0;
for (j = 0; j < 89; j++){
s[j] = a[j] + mess;
}
printf("%s\n", s);
fclose(ptof);
return 0;
}
s[j] = a[j] + mess needs a modulo operation as well
There's a lot of room for improvement here. Do you really want to map printable characters into (potentially) non-printable characters? Or do you merely want to do a ceaser shift on letters in the alphabet? Why the arbitrary limit of 90 characters of input? Using scanf is never a good idea (in 20 some years writing code, I have never used it since I left school). Passing the shift on stdin rather than as an argument makes it hard to use your program as a filter. For instance, it would be really nice if you could take a string and shift it by 4, then by 13, then by 9 and see that you get the original text back. (eg < file ceaser 4 | ceaser 13 | ceaser 9 | diff - file should report no diffs).
Here's a few ideas:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
FILE *
xfopen( const char *path, const char *mode )
{
FILE *ifp = fopen( path, mode );
if( ifp == NULL ) {
perror( path );
exit( 1 );
}
return ifp;
}
int
main( int argc, char **argv )
{
int mess = argc > 1 ? strtol( argv[1], NULL, 10 ) % 26 : 13;
FILE *ptof = argc > 2 ? xfopen( argv[2], "r" ) : stdin;
int c;
while( ( c = fgetc( ptof )) != EOF ) {
if( isupper( c ))
c = 'A' + ( c - 'A' + mess ) % 26;
if( islower( c ))
c = 'a' + ( c - 'a' + mess ) % 26;
putchar( c );
}
return 0;
}
I am writing a program that replaces characters in the user's input in C but I don't know how to replace the certain characters. Is there a certain method for C that replaces characters in a string? If you know python, then I want something a bit like this in python:
string.replace('certain_character','replacement_character')
Something like that, except for C, and not python.
This is my code that I have written so far:
#include <stdio.h>
int main(){
char str[BUFSIZ];
printf("Welcome To My Secret Language encoder!Enter some text: \n");
scanf("%s",str);
/*
Where I want to replace certain characters
*/
printf("Here is your text in secret language mode: %s \n",str);
}
I'm writing this code to learn C more, and that's why i'm not doing it in a higher level language like python.So, how do you replace certain characters in a string?
Nothing like that in C. You'll have to scan the string yourself:
#include <string.h>
char str[] = "I love cats";
int i;
for(i = 0; i < strlen(str); i++)
{
if(str[i] == 'c')
str[i] = 'b';
}
Now, if you're looking for a substring, you'll need something like strstr.
strchr finds the given character in a string, or returns NULL.
int main() {
int c;
while ( ( c = getchar() ) != EOF ) {
char const * found, * source = "abc", * dest = "xyz";
if ( ( found = strchr( "abc", c ) ) != NULL ) {
putchar( dest[ found - source ] );
} else {
putchar( c );
}
}
return 0;
}
If you have a lot of characters that you want to replace with other characters (like a Caesar cypher) you can build a lookup for yourself as follows:
#include <string.h>
char plain[] = "Hello there good people";
char encoder[26] = "ghijklmnopqrstuvwxyzabcdef";
char secret[100]; // long enough
int n = strlen(plain);
for(ii = 0; ii < n; ++ii) {
secret[ii] = encoder[(tolower(plain[ii]) - 'a')%26];
}
secret[n] = '\0';
This uses a couple of tricks:
cast all characters to lower case
subtract 'a' from the lowercase number - since a char is really just a number, we now have a == 0
Perform a modulo operation on the result so things that fall outside of the range of good characters don't cause a memory access error.
Add a '\0' at the end to make sure the string is properly terminated.
Copying things into a new string; obviously you could do an in-place replacement.
As written this will turn numbers (digits) and punctuation / symbols / spaces into characters. You could decide that anything that is not a letter is maintained - and maybe that only lower case letters are converted. In that case
#include <string.h>
char plain[] = "Hello there good people";
char encoder[26] = "ghijklmnopqrstuvwxyzabcdef";
char secret[100]; // long enough
int n = strlen(plain);
for(ii = 0; ii < n; ++ii) {
if(plain[ii] >= 'a' && plain[ii] <= 'z') {
secret[ii] = encoder[plain[ii] - 'a'];
}
else {
secret[ii] = plain[ii];
}
}
secret[n] = '\0';
there is no such function, you have to write one using strstr.
if you can use std::string, you can use string.replace()
Say you want to replace: A with z and b with X
char *replace(char *src, int replaceme, int newchar)
{
int len=strlen(src);
char *p;
for(p=src; *p ; p++)
{
if(*p==replaceme)
*p=newchar;
}
return src;
}
usage:
replace(string, 'A', 'z');
replace(string, 'b', 'X');
This is just the logic to do it, you need more statements in your code.