How should I solve this cipher with pointer arithmetic? - c

The question reads:
Solve the following cipher using Pointer Arithmetic. The given string is GKQTEHIN. Define a pointer and set it to the letter ‘T’ in this string. Traverse the string forward and backward. Add/subtract a single value (key) between 1 and 5 to each letter to solve this cipher and form a meaningful word. Hint: You will be using this as you solve it.
Hopefully this has been done correctly...
char given[]="GKQTEHIN";
char *pointer;
pointer=&given[3];
pointer-=3;
printf("%c", *pointer-4);
pointer+=1;
printf("%c", *pointer+4);
pointer+=1;
printf("%c", *pointer-4);
pointer+=1;
printf("%c", *pointer-4);
pointer+=1;
printf("%c", *pointer+4);
pointer+=1;
printf("%c", *pointer+4);
pointer+=1;
printf("%c", *pointer-4);
pointer+=1;
printf("%c\n\n", *pointer+4);
The word "COMPILER" is printed.

How do I "add/subtract a single value...to each alphabet"?
A computer only understands and works with numbers, since everything is a number (or can be considered a number) in a computer. This means letters are actually numbers internally. char in C uses ASCII encoding, which makes each letter correspond to a number. So you just add the key to the code representing that char. You can use char as a number with no problems.
char a = 'a';
a++;
printf("%c\n", a); // prints 'b'

To add some value to come char, use the following. You can do this for a whole string by looping over it.
int main()
{
char ch = 'a'; // or some other character
int x = 2; // or some other value
ch = (ch - 'a' + x) % 26 + 'a'; // make sure you have a value between 'a' and 'z'
printf("%c\n", ch); // prints 'c'
}

You need to apply two concepts here:
First, pointer is a variable that contains the address of one of the characters in given[].
If you add 1 to it, it will point to the next character. If you subtract 1 from it, it will point to the previous character.
But you need to keep it within the boundaries of the array. So pointer can never be less than &given[0] (or just given, which also evaluates to the address of the first element), and you should stop incrementing when it points to the null character (\0) at the end of the string. You can do this by creating a loop that increments pointer at each iteration, handles the boundary by resetting pointer to given when it points to the null character, and stops when it hits the T again.
Second, *pointer is the character that pointer points to.
You can change the character by adding to or subtracting from (*pointer). For example, you've initialized pointer to &given[3] (which is the same as given + 3), so it points to the letter T. So (*pointer) + 1 would be U, and (*pointer) - 2 would be R. If you want to save the new character, you can write
*pointer = (*pointer) - 2;
or just
(*pointer) -= 2;
You also need to worry about "falling off the end" of the alphabet. For example, (*pointer) + 7 would be the character after Z, but you probably want it to "wrap around" back to A. The simplest way to do this is to subtract 26 if *pointer > 'Z' (because there are 26 letters in the alphabet) or to add 26 if *pointer < 'A'. You can also use the modulus operator (%), but that's more complicated.
Putting that all together:
We know that we'll always be adding a constant value between -5 and 5.
We'll test each value by adding it to every character in the string and printing the result.
Here's an algorithm that will do that:
Create a loop with a variable, say key, that runs from -5 to 5.
Inside the loop, reset given to its initial string.
Also inside the loop, create a second loop that
initializes pointer to given + 3,
adds the value of key to the character at *pointer,
increments pointer during each iteration
wraps back to the beginning of the string when pointer hits the null character, and
stops when pointer gets back to given + 3 again.
I'll leave it to you to write the code. Feel free to update your question if you get stuck, and remember to add the code you've written!
Good luck!

You are basically traversing this, looking for a pattern:
-5 BFLO CDI
-4 CGMPADEJ
-3 DHNQBEFK
-2 EIORCFGL
-1 FJPSDGHM
+0 GKQTEHIN
+1 HLRUFIJO
+2 IMSVGJKP
+3 JNTWHKLQ
+4 KOUXILMR
+5 LPVYJMNS
but the instructions for traversal and key adding are clear as mud so you need to try each way (basically like a word search for an unknown word that spans the puzzle).
Forward and backward could mean all the way forward, then all the way back or forward and back simultaneously.
Adding a constant key (2, 3 or 4) would give you a row, but traversing rows forward and back from any point in a row appears to yield garbage, so that leaves the index (possibly with a constant) as a key variable, so you need to look at patterns like '//', '\', '/\', '/' backward and forward as well as from middle to end and end to middle, where the diagonal lines indicate direction.

Related

Is this undefined behaviour ( working with string literal)

#include<stdio.h>
int main()
{
char *s = "Abc";
while(*s)
printf("%c", *s++);
return 0;
}
I have seen this (on a site) as a correct code but I feel this is undefined behavior.
My reasoning:
Here s stores the address of the string literal Abc. So while traversing through the while loop :
Iteration - 1:
Here *(s++) increments the address stored in s by 1 and returns the non-incremented address (i.e the previous/original value of s). So, no problem everything works fine and Abc is printed.
Iteration - 2:
Now s points to a completely different address (which may be either valid or not). Now when trying to perform while(*s) isn't it undefined behavior ?
Any help would be really appreciated!
No. There's no undefined behaviour here.
*s++ is evaluated as *(s++) due to higher precedence of postfix increment operator than the dereference operator. So the loop simply iterates over the string and prints the bytes and stop when it sees the null byte.
Now s points to a completely different address (which may be either valid or not). Now when trying to perform while(*s) isn't it undefined behavior ?
No. In the first iteration s points to the address at the char A and at b in the next and at c in the next. And the loop terminates when s reaches the null byte at end of the string (i.e. *s is 0).
Basically, there's no modification of the string literal. The loop is functionally equivalent to:
while(*s) {
printf("%c", *s);
s++;
}
Iteration - 1:
Here *(s++) increments the address stored in s by 1 and returns the non-incremented address (i.e the previous/original value of s). So, no problem everything works fine and Abc is printed.
No, “Abc” is not printed. %c tells printf to expect a character value and print that. It prints a single character, not a string. Initially, s points to the first character of "Abc". s++ increments it to point to the next character.
Iteration - 2:
Now s points to a completely different address (which may be either valid or not). Now when trying to perform while(*s) isn't it undefined behavior ?
In iteration 2, s is pointing to “b”.
You may have been thinking of some char **p for which *p had been set to a pointer to "abc". In that case, incrementing p would change it to point to a different pointer (or to uncontrolled memory), and there would be a problem. That is not the case; for char *s, s points to a single character, and incrementing it adjusts it to point to the next character.
Now s points to a completely different address
Indeed, it is a completely different but well defined address. s referenced the next char of the string literal. So it just adds 1 to the pointer.
Because string literal is nul (zero) terminated the while loop will stop when s will reference it.
There is no UB.

I need to know how the output was generated by this source code

#include <stdio.h>
int main()
{
char c[]="GATE2016";
char *p = c;
printf("%s",p+ p[3] - p[1]);
}
The output to the above source code is
2016
I don't have the slightest clue how that came. Also when I edit
char c[]="asdf2016"
the output shown is
`
Can anybody help me in this?
First of all p is a pointer to the first element of the array c, so whenever you pass p alone it is going to behave exactly the same way as if you passed c, that is it will read from the adress of p until it reaches the string terminator '\0' .
Now, some say that it depends on whether your code uses ASCII or EBCDIC or any other encoding. While it's not wrong, your code does not depend immediatly on this. What matters is that, in the case of your string "GATE2016" the characters 'A' and 'E'(which are the ones accessed in this bizarre-looking code in the printf call) come one after the other and that substracting A from E gives 4, you'll see why. For the sake of this example, I'll use ASCII.
In ASCII, the characters 'A' equals 65, and 'E' equals 69. So in the line
printf("%s",p+ p[3] - p[1]);
what you are actually doing can be translated as
printf("%s",p+ 'E' - 'A');
or simply
printf("%s",p+ 69 - 65);
which can be further simplified as
printf("%s",p + 4);
Now since the "%s" format of printf expects a pointer to the beginning of a string, what you are actually passing as an argument in this case is the address of p + 4 (which since it's a pointer, gets shifted by 4 memory slots), so you end up with position [4] as the beginning of the string (p + 4 == &p[4]), printf starts reading your string at position 4, which contains the 2 of 2016. From there it just reads until it reaches '\0' in you string and just prints out 2016, which also explains why it does not work with "asdf".
Just remember that characters in C are simply numbers, and that, in ASCII, writing 'A' is exactly the same as writing the number 65.
Well,
First of all variable p is an address, as well as c. Second of all, characters are still represented as numbers internally. I assume that in your implementation the ASCII code dictates what that representation is, so in ASCII:
'E' = 69 and 'A'=65 ,
for more see ascii code
p[3] = 'E'
p[1] = 'A'
in your string and so that printf actually prints from p+4 meaning from p[4] till the end.

How to read an array and analyse the input

I was just wondering is there some way to read an array and then based upon the letters entered do something?
Like for example: if the roman numeral; MM was entered is there some way to see that 2 M's were entered and display the value for M?
output would be: 1000+1000.
Could you just tell me the name of the function, because it is for an assignment I dont want someone doing it for me, I just dont know where to start from.
example: char romanNumerals[2] = {"MMMCMXCVIII"};
char romanNumerals[2] = {"MMMCMXCVIII"};
Is not right as it can only hold 1 element(+1 for the \0). Change it to
char romanNumerals[] = "MMMCMXCVIII";
The compiler will choose the correct size for the array when doing the above initialization.
Then,you need a variable to add the sum of each roman number. So create
int sum=0;
And you need to loop the length of array times as you want to check each letter.
int i,len=strlen(romanNumerals);
for(i = 0;i < len;i++)
{
//body of for loop
}
string.h should be included in order to use strlen function which returns the length of a string.
Now,check each letter inside the body of the for loop using
if(romanNumerals[i]=='M')
sum=sum+1000;
else if(romanNumerals[i]=='C')
sum=sum+/*the corresponding value*/;
else if(...)
sum=sum+/*value*/;
//etc etc
And then at last,print sum.
Your best bet is to use the scanf function from stdio.h.
char str[3];
scanf("%s", str);
would store up to two characters from the standard input and the null terminator (\0) into the char array pointed at by str.
All other answers are correct, but keep in mind that if you just sum the input letters with a lookup (M=1000, C=100, X=10, V=5, I=1), having "MMMCMXCVIII" would mean 3000+100+1000+10+100+5+3 = 4218 and this is not what "MMMCMXCVIII" means in roman numerals (it actually means 3998 ).
For reasons explained in the link supplied by NSimon (see 1st comment) scanf() is not the best option when the input string length isn't known.
Other options are fgets() and getline(). The thing to remember is that a properly formed string is terminated by a null character - usually written '\0'. Hence if all else fails, you can always read char for char using the fgetc() function in a loop of some sort and stop when either your buffer is full or the '\0' is found.
So much for reading the array. When it comes to evaluating roman numerals, the best approach is to start at the back. Roman numerals have a (niot quite so simple) ordering:
I < V < X < L < C < D < M
Reading backwards you need to follow some straight forward rules:
The least significant packet is always last (i.e. IXL is wrong, it should be LIX = 59)
If X or V is preceeded by I then subract 1 otherwise add the value.
If L or C is preceeded by X then subtract 10 otherwise add the value.
If D or M is preceeded by C then subtract 100 otherwise add the value.
Note that M & D can only ever be preceeded by C or M. L & C can only be preceeded by X or C. X & V can only be preceeded by I or X. Anything else indicates a malformed number.
Thus working from the back it should be reasonably easy to obtain the correct value.

Usage of function putc

I am working on a C program that I did not write and integrating it with my C++ code. This C program has a character array and usage putc function to print the content of it. Like this:
printf("%c\n","01"[b[i]]);
This is a bit array and can have either ASCII 0 or ASCII 1 (NOT ASCII 48 and 49 PLEASE NOTE). This command prints "0" and "1" perfectly. However, I did not understand the use of "01" in the putc command. I can also print the contents like this:
printf("%d\n",b[i]);
Hence I was just curious. Thanks.
Newbie
The "01" is a string literal, which for all intents and purposes is an array. It's a bit weird-looking... you could write:
char *characters = "01";
printf("%c\n", characters[b[i]]);
or maybe even better:
char *characters = "01";
int bit = b[i];
printf("%c\n", characters[bit]);
And it would be a little easier to understand at first glance.
Nasty way of doing the work, but whoever wrote this was using the contents of b as an array dereference into the string, "01":
"foo"[0] <= 'f'
"bar"[2] <= 'r'
"01"[0] <= '0'
"01"[1] <= '1'
your array, b, contains 0s and 1s, and the author wanted a way to quickly turn those into '0's and '1's. He could, just as easily have done:
'0' + b[i]
But that's another criminal behavior. =]
The String "01" is getting cast into a character array (which is what strings are in C), and the b[i] specifies either a 0 or a 1, so the "decomposed" view of it would be.
"01"[0]
or
"01"[1]
Which would select the "right" character from the char array "string". Note that this is only possible C due to the definition that a string is a pointer to a character. Thus, the [...] operation becomes a memory offset operation equal to the size of one item of the type of pointer (in this case, one char).
Yes, your printf would be much better, as it requires less knowledge of obscure "c" tricks.
This line is saying take the array of characters "01" and reference an array element. Get that index from the b[i] location.
Thus "01"[0] returns the character 0 and "01"[1] returns the character 1
Do the statement you understand.
Simplifying the other one, by replacing b[i] with index, we get
"01"[index]
The string literal ("01") is of type char[3]. Getting its index 0 or 1 (or 2) is ok and returns the character '0' or '1' (or '\0').

C, sprintf and "sum" of string and int

I didn't used C for a lot of time, and now I have to modify a little piece of code. There one thing I can't understand:
char filename[20];
filename[0] = '\0';
for (j=0; j < SHA_DIGEST_LENGTH; j++){
sprintf(filename + strlen(filename),"%02x",result[j]);
}
In the first line a string of 20 characters is dleclared.
In the second line the first char is set to '\0', so is an empty string, I suppose.
In the for loop I don't understand the "sum" between filename and its length... The firs parameter of sprintf should be a buffer where to copy the formatted string on the right. What is the result of that sum? It seems to me like I'm trying to sum an array and an integer...
What I'm missing?
It's pointer arithmetic. strlen returns the number of characters before the NUL terminator. The result of the addition will point to this terminator. E.g. if the current string is "AA" (followed by a NUL), strlen is 2. filename + 2 points to the NUL. It will write the next hex characters (e.g. BB) over the NUL and the next character. It will then NUL-terminate it again (at filename + 4). So then you'll have "AABB" (then NUL).
It doesn't really make sense though. It wastes a lot of time looking for those NULs. Specifically, it's a quadratic algorithm. The first time, it examines 1 character, then 3, 5, 7, ..., 2 * SHA_DIGEST_LENGTH - 1) that . It could just be:
sprintf(filename + 2 * j,"%02x",result[j]);
There's another problem. A hexadecimal representation of a SHA-1 sum takes 40 characters, since a byte requires two characters. Then, you have a final NUL terminator, so there should be 41. Otherwise, there's a buffer overflow.
Why dont you declare
char filename[SHA_DIGEST_LEN*2 +1]; /* And +1 if you want to have the NULL terminating char*/
This is because SHA1 digest length is 20 bytes, if you were just to print the digest then you may probably not want the additional memory but since you want hexadecimal string of the digest you can use the above declaration.
A strlen operation returns lenghth of string till a null terminating character is encountered.
So basically when you do the following :
sprintf(filename + strlen(filename),"%02x",result[j]);
In the first interation filname is copied with 2 bytes of the hexadecimal representation of the first byte of the sha-1 digest. Eg. Say that is AA, now you need to move your pointer two places to copy the next byte.
After second iteration it becomes AABB.
After the 20th iteration you have the entire string AABBCC......AA[40 bytes] and +1 if you need the '\0' which is the NULL termination character.
First iteration, when j = 0, you will write 3 chars (yes, including the '\0' terminating the string) onto the beginning of filename, since strlen() then returns 0.
Next round, strlen() returns 2, and it will continue writing after the first two chars.
Be careful for stepping outside the 20 char space allocated. Common mistake is to forget the space required for the string terminator.
EDIT: make sure that SHA_DIGEST_LENGTH is not greater than 9.
you are adding strlen(filename) only to do concatenation of result[j]
Each iteration concatenates the current result[j] at the end of filename so each time you need to know to offset within the filename where the concatenation should take place.
Replace the code with:
char filename[SHA_DIGEST_LENGTH*2+1];
for (j=0; j < SHA_DIGEST_LENGTH; j++){
sprintf(filename + 2*j,"%02x",result[j]);
}
Faster, simpler, and the bugs are gone.

Resources