Possible combinations of characters on a phone's numpad - c

I was faced with a question recently in C. We have a phone's numpad with following layout:
1[abc] 2[def] 3[ghi]
4[jkl] 5[mno] 6[pqr]
7[st] 8[uv] 9[wx]
0[yz]
How to come up with an API which gives all possible combinations of characters belonging to each number for a given numeral input.
For e.g. input = 1234
Then the API should print all possible combinations of characters-
adgj bdgj cdgj aegj begj cegj.. and so on.
Is there a simple way to do it? Apart from hardcoded nested for loops.
I was given a hint as recursion but couldn't figure a way out of it.

Recursion is a good solution for such problems, where you must find combinations. The advantage over nested loops is that recursion works for strings of any length.
In your case, you need a function that takes:
the original string
an auxiliary char buffer for the solution* and
the current index, which starts at 0.
Recursive functions require a termination condition: When you have reached the end of the original string, print it and return.
Otherwise, take the next digit, check whether it is valid, determine the letters associated with it and then call the function for each of the letters. That is, for each letter, copy it to the solution at the current index, then call the function with the next index.
Below's an example implementation that uses an intermediate function to do some house-keeping:
#include <stdlib.h>
#include <stdio.h>
/*
* Recursive back-end, that produces all combinations in sol.
*/
void alpha_r(const char *str, char *sol, int index)
{
const char *combo[] = {
"yz", "abc", "def", "ghi", "jkl", "mno", "pqr", "st", "uv", "wx"
};
if (str[index] == '\0') {
printf("%s\n", sol);
} else {
int k = str[index] - '0';
const char *p = combo[k];
while (*p) {
sol[index] = *p++;
alpha_r(str, sol, index + 1);
}
}
}
/*
* Non-recursive front-end that checks the string for validity
* and creates a temporary buffer for the solutions.
*/
void alpha(const char *str)
{
int len = 0;
while (str[len]) {
if (str[len] < 0 || str[len] > '9') {
fprintf(stderr, "Invalid input.\n");
return;
}
len++;
}
char sol[len + 1];
sol[len] = '\0';
alpha_r(str, sol, 0);
}
int main()
{
alpha("123");
return 0;
}
*) You could also use the string itself to store the solutions.

(That is not the standard layout for a phone, by the way.)
The tricky part is handling the data structures. It is handy that the input string consists of numbers, because then we can use the digits in the string to index an array that holds the possible letters for each number.
The idea is to modify an output string at a particular index using a for loop to go over all the possible replacements at that index. Then recursively move to the next index in the output array in the body of the for loop.
If you reach the end of the array, then print and return.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char* data[] = {"0", "1", "2abc", "3def", "4ghi", "5jkl", "6mno", "7prs", "8tuv", "9wxy"};
char* input = "23456783";
char* arr;
void current(int index)
{
if(index == strlen(input)) printf("%s\n", arr);
else
{
for(int i = 0; i < strlen(data[input[index] - '0']); ++i)
{
arr[index] = data[input[index] - '0'][i];
current(index + 1);
}
}
}
void main()
{
arr = malloc(strlen(input) + 1);
arr[strlen(input)] = '\0';
printf("%s\n\n", input);
current(0);
}

A way to find the combinations that you are looking for could be bitwise logic, with a binary number and an integer. The binary number would be as long as the string, with 0's and 1's acting as on and off switches for what is included and excluded in the string. The thing here is that we use base 3 or 4 depending on the number "pressed", and
If base four, then some if statements have to be applied to move the ones along that are actually base three.

Recursion is just a sneaky way of nesting four for loops. Here's what the code looks like
#include <stdio.h>
void sneaky( int depth, int maxDepth, char str[] )
{
char c, start;
start = 'a' + depth * 3;
for ( c = start; c < start + 3; c++ )
{
str[depth] = c;
str[depth+1] = '\0';
if ( depth == maxDepth )
printf( "%s\n", str );
else
sneaky( depth + 1, maxDepth, str );
}
}
int main( void )
{
char str[5] = { 0 };
sneaky( 0, 3, str );
}
You can also solve this problem, and similar combinatorial problems, with a simple counting algorithm. A counting algorithm emulates natural counting, in which you increment the least significant digit from 0 to 9. When the least significant digit wraps from 9 back to 0, the next digit to the left is incremented.
The same can be done to solve the OP's problem. But in this case, the digits have either two or three possible values. And if you examine the pattern in the OP, it's readily apparent that the least significant digit is on the left. In the pattern
adgj bdgj cdgj aegj
you can see that a becomes b, b becomes c, and when c wraps back to a, then d becomes e.
Here's the code
#include <stdio.h>
#include <stdlib.h>
static char InitialValue[] = { 'y', 'a', 'd', 'g', 'j', 'm', 'p', 's', 'u', 'w' };
static char NextValue[] = { 'b', 'c', 'a', 'e', 'f', 'd', 'h', 'i', 'g',
'k', 'l', 'j', 'n', 'o', 'm', 'q', 'r', 'p',
't', 's', 'v', 'u', 'x', 'w', 'z', 'y' };
static void error( char *msg )
{
fprintf( stderr, "%s\n", msg );
exit( EXIT_FAILURE );
}
int main( void )
{
int i, oldDigit;
char str[12];
// get the input string from the user
printf( "Enter the input string: " );
fflush( stdout );
if ( scanf( "%10s", str ) != 1 )
error( "whatever" );
// convert the input string to the corresponding first output string
for ( i = 0; str[i] != '\0'; i++ )
{
if ( str[i] < '0' || str[i] > '9' )
error( "invalid input string" );
str[i] = InitialValue[str[i] - '0'];
}
printf( "%s\n", str );
// use a simple counting algorithm to generate the string combinations
for (;;)
{
for ( i = 0; str[i] != '\0'; i++ )
{
oldDigit = str[i]; // save the current digit
str[i] = NextValue[oldDigit - 'a']; // advance the digit to the next value
if ( str[i] > oldDigit ) // if the digit did not wrap
break; // then we've got a new string
}
if ( str[i] == '\0' ) // if all the digits wrapped
break; // then we're done
printf( "%s\n", str ); // output the new string
}
return( EXIT_SUCCESS );
}

Related

fgets exploit - reverse engineering with IDA

I'm currently doing an exercise, where I have to find a way to "pass" the level (It's a reverse engineering exercise, I decompiled it with IDA).
The level function consists of 3 while loops, from each I have to break to get to the next one. To pass the level, I have to input something that will pass through the 3 checks.
Code is as follows:
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
memset(Buffer, 0, sizeof(Buffer));
stream = _acrt_iob_func(0);
fgets(Buffer, 1020, stream);
if ( strlen(Buffer) >= 0x1E )
break;
}
if ( first_check_string(Buffer) )
break;
}
if ( second_check_string(Buffer) )
break;
}
return printf(aWellDone, Buffer[0]);
}
The first_check_string function:
int __cdecl first_check_string(_BYTE *str_addr)
{
while ( *str_addr )
{
if ( (char)*str_addr < 97 || (char)*str_addr > 122 )
return 0;
if ( ((char)*str_addr - 97) % 3 )
return 0;
++str_addr;
}
return 1;
}
The second_string_check function:
BOOL __cdecl second_check_string(char *Str)
{
int v2; // [esp+4h] [ebp-8h]
char *i; // [esp+8h] [ebp-4h]
if ( strlen(Str) % 4 )
return 0;
v2 = 0;
for ( i = Str; *(_DWORD *)i; i += 4 )
v2 ^= *(_DWORD *)i;
return v2 == 1970760046;
}
For the first if, i just have to enter a string longer than 1E, or 30 in decimal.
The second, I have to enter only a-z character, but only ones that their ascii - 97 is divisible by 3. So only options are: a, d, g, j, m, p, s, v, y.
But there's a catch - I have to enter at least 1019 characters, since otherwise, the fgets will get the newline 0x0A character, and the first_check_string function will not pass.
So I enter 1019 "a"s for example.
I pass the first 2 ifs. But the 3rd if function second_check_string requires my string to be divisble by 4, which can't be if I enter 1019 chars. And if I enter less, the first_check_string function will encounter the 0x0A newline char and return 0.
If anyone got any idea of how could I approach this, I would be grateful.
GENERALIZED SOLUTION
To enter a NUL 0x00 byte, we need to redirect the program to read from a file instead from the user's keyboard.
To do so, we execute the program as follows:
prog.exe < file
this makes the standard input, which fgets uses, become the file.
In the file we can any bytes we want, including the NUL character.
We can do so either by using a programming language to write to that file, or a hex editor (I used 010 editor).
Cheers to EVERYONE who helped me!
Input a manual NUL character, '\0' at one past a multiple of 4 offset (so the apparent string length is a multiple of 4). fgets will happily retrieve it as part of a string without stopping, but your tests using C-style string definition will stop at the NUL, and never see a following newline, nor any other character violating the rules being checked. This dramatically relaxes the restrictions; make it long enough to pass the basic break in the innermost loop, then put a NUL after a multiple of four characters has been entered, and after that you can enter anything for the remainder of the 1019 characters because the rules won't be checked past the NUL.
Kudos to #Shadowranger for noting the that a strategic \0 simplifies the problem immensely!
The following is a minor adaptation of the code given in the original problem.
int first_check_string( char *cp ) {
while ( *cp ) {
if( !islower( *cp ) ) // 'a'- 'z'
return 0;
if ( (*cp - 'a') % 3 ) // but only every third of those pass muster
return 0;
++cp;
}
puts( "Passed 1st check" );
return 1;
}
bool second_check_string(char *Str) {
int v2; // [esp+4h] [ebp-8h]
char *i; // [esp+8h] [ebp-4h]
if ( strlen(Str) % 4 )
return 0;
v2 = 0;
for ( i = Str; *(uint32_t *)i; i += 4 )
v2 ^= *(uint32_t *)i;
printf( "Aiming for %08X... Got %08X\n", 1970760046, v2 );
return v2 == 1970760046;
// Hides 0x7577696E as a decimal value
// ASCII decoding: 0x75-'u', 0x77-'w', 0x69-'i', 0x6E-'n' ==> "uwin"... :-)
}
int main() {
char Buffer[1020] = {
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
0, 0, 0, 'd', 0, 0, 0, 'd',
'n', 'i', 'w', 'u', 0, 0, 0, 0, // 7577696E = 'u', 'w', 'i', 'n';
};
while( 1 ) {
while ( 1 ) {
while ( 1 ) {
/* Using compile-time array instead of loading binary file */
if ( strlen(Buffer) >= 0x1E )
break;
}
if ( first_check_string(Buffer) )
break;
}
if ( second_check_string(Buffer) )
break;
else {
puts( "Failed 2nd check" );
getchar();
}
}
puts( "Well Done" );
return 0;
}
Passed 1st check
Aiming for 7577696E... Got 7577696E
Well Done
The 1st 32 bytes followed by 0 satisfy the minimum string length. (The compile time array skirts the OP problem of reading up to 1020 bytes, with an embedded NULL, from a file. The effect is the same, regardless.)
The XOR of those (even quantity) 'a' characters results in zero; a clean start for more processing.
The XOR of bytes 32-35 (treated as an unsigned int) with the next 4 bytes means that v2 is still zero...
Finally, hidden behind that NULL (thanks Shadowranger), and all those balancing XOR's, is the literal unsigned integer (32 bits) that is the key to matching. Note that 'endian-ness' comes into play, and the "u win" message must be reversed (on my hardware).
And the next 4 NULL bytes will terminate the 2nd check, so anything in the buffer beyond that is ignored...
Good fun!

C Array: How can I shift each character in a string?

I am new to C, and I am learning shift operation.
I understand the shift operation if the data is a binary number, but for my code in this case, I want to implement the case that 't', 'h', 'i', 's', ' ', '\0' are all discarded or shifted, and move 'a' to the first element of this string.
Can I do this behavior by using shift operator? If so, why is so?
Really appreciated.
char words[10] = {'t', 'h', 'i', 's', ' ', '\0', 'a', 'b', 'c'};
The shift operator you are talking about is basically bitwise operator. You can't use this to shift array of characters.
To accomplish what you asked, you can write a function. Suppose you want left shift -
int leftShift(char *words, int len)
{
int i;
for(i = 1; i < len; i++)
{
words[i - 1] = words[i];
}
len--;
return len;
}
What this function does? - it takes an array and length of that array as parameter, and perform left shift one time.
So then from your main function you can just call this method any number of times you want -
int main(void) {
char words[10] = {'t', 'h', 'i', 's', ' ', '\0', 'a', 'b', 'c'};
int len = 10;
len = leftShift(words, len); // left shift one time - this will discard 't'
len = leftShift(words, len); // left shift one time - this will discard 'h'
//finally print upto len, because len variable holds the new length after discarding two characters.
int i;
for(i = 0; i < len; i++)
{
printf("'%c', ", words[i]);
}
return 0;
}
This is very trivial idea, surely this approach can be improved in many ways. But I think you got the basic idea.

String compare in C

I'm a little confused with the string compare strcmp() function in C.
When you have two strings, grass and grapes and you use strcmp(grass, grapes); which results in 39, or any positive number, does this mean that "grapes" is alphabetized before "grass", or the opposite?
I know that if it results to 0, they're equal.
strcmp function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ or until a terminating null-character is reached.
This means that, this function performs a binary comparison of the characters.
The following program should give you an Idea about how strcmp works:
#include <stdio.h>
#include <string.h>
int stringcmp(char *s1, char *s2){
int count = 0;
while (s1[count] == s2[count]) {
if (s1[count] == '\0' || s2[count] == '\0')
break;
count++;
}
if (s1[count] == '\0' && s2[count] == '\0'){
return 0;
}
if(strlen(s1) < strlen(s2)){
return -1;
}else{
return 1;
}
}
int main(void){
char *b = "grass";
char *a = "grapes";
if(stringcmp(a, b) == 0){
printf("Are equal.\n");
printf("Length of A = %zu\n",strlen(a));
printf("Length of B = %zu\n",strlen(b));
printf("Return of stringcmp = %d\n",stringcmp(a, b));
}else{
printf("Are not equal.\n");
printf("Length of A = %zu\n",strlen(a));
printf("Length of B = %zu\n",strlen(b));
printf("Return of stringcmp = %d\n",stringcmp(a, b));
}
return 0;
}
Output:
Are not equal.
Length of A = 5
Length of B = 6
Return of stringcmp = -1
If you swap a with b you get:
Are not equal.
Length of A = 6
Length of B = 5
Return of stringcmp = 1
And if A and B are the same:
Are equal.
Length of A = 5
Length of B = 5
Return of stringcmp = 0
The return value of strcmp is defined in C99 7.21.4
The sign of a nonzero value returned by the comparison functions memcmp, strcmp,
and strncmp is determined by the sign of the difference between the values of the first
pair of characters (both interpreted as unsigned char) that differ in the objects being
compared.
So if the result is positive, it means the second argument comes after the first.
It's not exactly alphabetical order, but is rather dependent on the underlying encoding of the characers. For instance, in ASCII, 'B' < 'a', because 'B' is encoded as 66 and 'a' is 97. If the characters are all letters of the same case, this will be equivalent to alphabetical order in all (non-multibyte) encodings I'm familiar with, but I don't believe this is required.
For cases like "grass" vs "grapes", it'll just keep scanning until it finds characters that differ ('s' vs 'p' in this case), and then make the decision. A special case of this is when one string is a substring of another: e.g. "grape" vs "grapes". For that case, you just need to remember that "grape" is actually { 'g', 'r', 'a', 'p', 'e', '\0' }, and apply the normal rule: '\0' < 's', so "grape" comes before "grapes".
This would be a conforming implementation of strcmp:
int strcmp(const char *a, const char *b) {
size_t i = 0;
while (a[i] || b[i]) {
if (a[i] != b[i]) {
if (a[i] < b[i]) return -1;
else return 1;
}
i++;
}
return 0;
}

C program doesn't work correctly

#include <stdio.h>
#include <string.h>
void main()
{
char alfavita[30] =
{
'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'
};
char str[20];
printf("Give a word:\n");
gets(str);
for(int i=0;i<strlen(str);i++)
{
for(int j=0;j<strlen(alfavita);j++)
if(alfavita[j] == str[i])
str[i] = alfavita[j+3];
}
puts(str);
}
For example if i give 'a' it should be return 'd' (each letter will transform into the 3d next of the alfavita array ) But it just prints me a null string. I can't find something wrong or I don't see it .
str[i] = alfavita[j+3];
After this line the code continues, so it will put i+3, i+6, ... until it gets out of alfavita.
You can add a break to exit the inner loop like that:
for(int i=0;i<strlen(str);i++)
{
for(int j=0;j<strlen(alfavita);j++)
if(alfavita[j] == str[i])
{
str[i] = alfavita[j+3];
break; // next i.
}
}
, or maybe just directly access the array:
for(int i=0;i<strlen(str);i++)
{
char c = str[i];
if (c >= 'a' && c <= 'z') {
str[i] = alfavita[(c - 'a' + 3) % strlen(alfavita)];
}
}
Note the % strlen(alfavita) to avoid ending after the end of the list.
You could also write it:
if (c >= 'a' && c <= 'z') {
str[i] = ((c - 'a' + 3) % 26) + 'a';
}
You can use a table that gives the replacement character for each character.
Then encode by computing the index into plain, and transferring that index into encoded:
char encode_char(char c)
{
const char *plain = "abcdefghijklmnopqrstuvwxyz";
const char *encoded = "defghijklmnopqrstuvwxyzabc";
const char *pp = strchr(plain, c);
if(pp != NULL)
return encoded[(ptrdiff_t) (pp - plain)];
return '?';
}
How the above works:
Define two strings that are supposed to be 1:1 mapped, i.e. plain[0] is encoded into encoded[0]. This can be more clearly modelled (i.e. by a struct that has the pair) but then the iniialization becomes more complicated.
Search for the input character c inside the plain string. This returns NULL if not found, or a pointer to somewhere inside plain found.
Make sure the pointer isn't NULL before using its value.
Subtract plain (i.e. &plain[0], the address of the a) from pp. This evaluates to 0 for a, 1 for b, and so on.
Use the computed index to look up the corresponding character in encoded.
On failure to encode, return ?.
In a portable, general program, you can not use plain subtraction (i.e. c - 'a'), since C does not guarantee that characters are encoded in values next to each other.
As pointed out, the above assumes that each character encodes in exactly one char. That might not be true for targets with exotic encodings, in which case it really is safer to use an explicit table, like this:
const struct {
char plain;
char encoded;
} encoding[] = {
{ 'a', 'd' },
{ 'b', 'e' },
{ 'c', 'f' },
/* ... and so on ... */
};
The encoding function then becomes:
char encode_char2(char c)
{
for(size_t i = 0; i < sizeof encoding / sizeof *encoding; ++i)
{
if(encoding[i].plain == c)
return encoding[i].encoded;
}
return '?'; /* Not found. */
}

How To Replace A Certain Character in C

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.

Resources