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').
Related
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.
I'm still new to the forum so I apologize in advance for forum - etiquette issues.
I'm having trouble understanding the differences between int arrays and char arrays.
I recently wrote a program for a Project Euler problem that originally used a char array to store a string of numbers, and later called specific characters and tried to use int operations on them to find a product. When I used a char string I got a ridiculously large product, clearly incorrect. Even if I converted what I thought would be compiled as a character (str[n]) to an integer in-line ((int)str[n]) it did the exact same thing. Only when I actually used an integer array did it work.
Code is as follows
for the char string
char str[21] = "73167176531330624919";
This did not work. I got an answer of about 1.5 trillion for an answer that should have been about 40k.
for the int array
int str[] = {7,3,1,6,7,1,7,6,5,3,1,3,3,0,6,2,4,9,1,9};
This is what did work. I took off the in-line type casting too.
Any explanation as to why these things worked/did not work and anything that can lead to a better understanding of these ideas will be appreciated. Links to helpful stuff are as well. I have researched strings and arrays and pointers plenty on my own (I'm self taught as I'm in high school) but the concepts are still confusing.
Side question, are strings in C automatically stored as arrays or is it just possible to do so?
To elaborate on WhozCraig's answer, the trouble you are having does not have to do with strings, but with the individual characters.
Strings in C are stored by and large as arrays of characters (with the caveat that there exists a null terminator at the end).
The characters themselves are encoded in a system called ascii which assigns codes between 0 - 127 for characters used in the english language (only). Thus "7" is not stored as 7 but as the ascii encoding of 7 which is 55.
I think now you can see why your product got so large.
One elegant way to fix would be to convert
int num = (int) str[n];
to
int num = str[n] - '0';
//thanks for fixing, ' ' is used for characters, " " is used for strings
This solution subtracts the ascii code for 0 from the ascii code for your character, say "7". Since the numbers are encoded linearly, this will work (for single digit numbers). For larger numbers, you should use atoi or strtol from stdlib.h
Strings are just character arrays with a null terminating byte.
There is no separate string data type in c.
When using a char as an integer, the numeric ascii value is used. For example, saying something like printf("%d\n", (int)'a'); will result in 97 (the ascii value of 'a') being printed.
You cannot use a string of numbers to do numeric calculations unless you convert it to an integer array. To convert a digit as a character into its integer form, you can do something like this:
char a = '2';
int a_num = a - '0';
//a_num now stores integer 2
This causes the ascii value of '0' (48) to be subtracted from ascii value '2' (50), finally leaving 2.
char str[21] = "73167176531330624919"
this code is equivalent to
char str[21] = {'7','3','1','6','7','1','7','6','5',/
'3','1','3','3','0','6','2','4','9','1','9'}
so whatever stored in str[21] is not numbers, but the char(their ASCII equivalent representation is different).
side question answer - yes/no, the strings are automatically stored as char arrays, but the string does has a extra character('\0') as the last element(where a char array need not have such a one).
I ripped this from an ebook on C programming.
I understand that ASCII representations of the characters '0' and '9' are integers, so I understand the compatibility with the integer array. I am simply not sure how the shown output is computed? There input is the code itself.
What does this statement mean?
++ndigit[c-'0'];
So, is the program essentially checking if the input is one of the first 10 installments of of the ASCII code table?
ASCII CODE
No, it doesn't.
c - '0' subtracts the (not necessarily ASCII) character code of the character 0 from that of c. This will yield a number between 0 and 9 if c is a digit. Then, the resulting integer is used to index the zero-initialized ndigit array using the [] operator, and the prefix increment operator (++) is then used to increment the element at that particular index.
By the way, the code is erroneous at multiple places. I suggest you switch to another book because this one appears to be either outdated and/or encouraging the use of several types of bad programming practice.
First, main() doesn't have a return type, which is an error. It needs to be declared as int main() or int main(void) or int main(int, char **). Older compilers had the bad habit of assuming an implicit int return type if it was omitted, but this behavior is now deprecated.
Second, it would be better to initialize the ndigit array, like this:
int ndigit[10] = { 0 };
The for loop is superfluous because we can have initialization; it's also less readable than the initialization syntax, and it's also dangerous: the author doesn't calculate the count of the array using sizeof(ndigits) / sizeof(ndigits[0]), but he hardcodes its length, which may cause a buffer overrun when the length of the array is changed (decreased) and the hard-coded length value in the for loop is forgotten about.
The program computes the number of times a digit between 0 and 9 was introduced as input, how many white spaces and how many other characters were in the input.
++ndigit[c-'0'];
'0' - as integer is the ASCII code for 0.
c - is the read character (its ASCII code)
c - '0' = the actual digit (between 0 and 9) represented by the ASCII code c.
For example '3'(ASCII) would be 3(digit=integer) + '0'(ASCII)
So that's how you obtain the index in the array for your digit and you increment the number of times that digit showed up.
In a c-book I bought, an exercise program is given as
what is the output for the following code snippet?
printf(3+"Welcome"+2);
the answer I got is me (by executing it in TC++)
But I can't get the actual mechanism.
please explain me the actual mechanism behind it.
It's called pointer arithmetic: 2+3=5, and "me" is the rest of the string starting at offset 5.
PS: throw away that book.
When this is compiled the "Welcome" string becomes a const char *, pointing to the first character of the string. In C, with character strings (like any pointer), you can do pointer arithmetic. This means pointer + 5 points to 5 places beyond pointer.
Therefore ("Welcome" + 5) will point 5 characters past the "W", to the substring "me."
On a side note, as other have suggested, this doesn't sound like a good book.
A string (like "Welcome") is an array of characters terminated by the NUL-character (so it's actually "Welcome\0").
What you are doing, is accessing the fifth character of it (3 + 2 = 5). This character is 'm' (array indices start at 0).
printf will continue to read till it hits the NUL-character.
I'm working through a book exercise to generate some random serial number, and here's my function:
NSString *randomSerialNumber = [NSString stringWithFormat:#"%c%c%c%c%c",
'0' + random() % 10,
'A' + random() % 26,
'0' + random() % 10,
'A' + random() % 26,
'0' + random() % 10];
This works and has an output like: 2J6X7. But before, the 0s and As I had wrapped in double quotes, and an example output was 11764ıÒ˜. What did I do wrong my first time around, and why did using single quotes fix it?
The difference between single and double quotes is that double quotes declare a string, and single quotes declare a single character. Try doing this, you will get a syntax error:
'More than one character'
The reason that your code outputted a bunch of random characters is that strings are not integers like most other data types, but pointers. This means that when you type "A string", the result of the expression is the memory location that the characters are stored at. This could be anywhere in memory, depending on when you start the program. So, when you added random() to the string, it gave you a random memory address! The statement was equivalent to this in English:
Store the characters "A" in memory, and then give me the memory
address a random amount of cells later.
The random amount of cells later could be anything else in your program. The pointer was interpreted as an character (because of %c), but it wasn't meant to, giving you seemingly random output.
The single quotes are giving you an ASCII representation of each character (char), to which you are adding a number. The double quotes give you a string (char *), to which adding a number really doesn't make much sense.
I might be wrong here, but I think at least the first half is right!
Single quotes are used for single character constants. Double quotes are used for strings, either C strings or NSStrings (which have '#' prefixes). When you used double quotes, the + meant pointer arithmetic. The resulting pointers were passed where characters were expected, which leads to undefined behavior. The correct version does integer arithmetic on the chars, which works as expected.
The numbers that you use for modulus controls how many ASCII characters after the one specified within the single quotes that can show up in the final string. Take a look at this table: http://www.asciitable.com/, for a reference on the ASCII numbers.
'0' + random() % 10 will give you characters from '0' to '10'
'A' + random() % 26 will give you characters from 'A' to 'Z'
Apologies if this is really obvious..
I'd like to add a question to this: is there a nice way to generate a similar string using regular expressions instead?
Adrian's answer is right. I'm just trying to add clarification.
"A" does three things.
It reserves space for 2 characters, the A and a nul terminator.
It puts the codes which represent those two characters in that space.
It returns the address of the first one.
That address is of the type: char *
'A' just returns the value of the code for A,
the same value as was put in the first memory cell above.
the value is of type char.
So as you can see there is a big difference.