CS50 Pset 2- ceasar cipher - c

It isn't showing what I want it to show that is the ciphered version of the input text but instead symbols, as I guess, looks kinda like a '?' comes out as the output in the terminal. could anyone help me in finding what I missed or did wrong?
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(int argc, string argv[])
{
if (argc == 2)
{
string ptext = get_string("plaintext: ");
int key = (int) argv[1];
printf("ciphertext: ");
for (int i = 0, n = strlen(ptext); i < n; i++)
{
printf("%c", (( ptext[i] + key ) % 26);
}
printf("\n");
}
else
{
printf("Invalid input. \n");
}
}
I expect the output of 'hello' to be 'ifmmp' but instead, it doesn't.

This code is wrong:
int key = (int) argv[1];
argv is an array of string, which in CS50 is nothing more than an obfuscated char * pointer.
Per 5.1.2.2.1 Program startup of the C standard:
The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent; ...
So argv[1] is a char * pointer value, which you then assign to an int value. That's taking the address of some memory (say the value in argv[1] is 0xFF0403220020480C) and trying to stuff it into the likely 4 bytes of the int variable key (which in this case would be assigned the truncated value 0x0020480C.)
That's not what you appear to be trying to do.
(IMO, your problem here is a perfect example of why CS50's obfuscation of char * with the string type is a tremendously bad idea. You simply can't understand C without understanding pointers and NUL-terminated char strings accessed via a char * pointer, and the obfuscation that string does makes that harder.)
If you want to convert a string to a numeric value, you likely want something like strtol() (never use atoi() as it has no error checking and its use can invoke undefined behavior):
char firstCharNotConverted;
// set errno to zero as strtol()
errno = 0;
long key = strtol( argv[ 1 ], &firstCharNotConverted, 0 );
// if errno is now non-zero, the call to strtol() failed (per Linux man page)
// need to examine key and the contents of firstCharNotConverted
// to figure out why
if ( errno != 0 )
{
...
}
Proper headers omitted as an exercise for anyone trying to use this code ;-)
Note that I used long for key, as you can't do complete and proper error checking on strtol() if you cast the return value to int.
Error checking strtol() can be somewhat complex as the value returned (and assigned to key in the above code) can be any value and there are no values possible that aren't legitimate long values that strtol() can return to indicate an error, so for proper error checking you need to check the values of both errno and firstCharNotConverted to properly determine if an error did occur. The Linux man page states:
Since strtol() can legitimately return 0, LONG_MAX, or LONG_MIN
(LLONG_MAX or LLONG_MIN for strtoll()) on both success and failure,
the calling program should set errno to 0 before the call, and then
determine if an error occurred by checking whether errno has a
nonzero value after the call.
After that call to strtol(), you need to check if key is LONG_MIN, or LONG_MAX with errno equal to ERANGE for underflow or overflow, or if key is 0 you need to check the contents of firstCharNotConverted to determine why the conversion may have failed. Note that if key is zero and firstCharNotConverted isn't equal to argv[ 1 ], then input string was properly converted from zero.
Your Ceaser cipher implementation is also wrong:
for (int i = 0, n = strlen(ptext); i < n; i++)
{
printf("%c", (( ptext[i] + key ) % 26);
}
printf("\n");
will just print out characters with values from 0 through 25 - which aren't letters in the ASCII character set.
There a numerous Ceaser ciphers questions already posted here, so I'm not going to write the code. See Caesar's Cipher Code for one example question.

The problem is here printf("%c", (( ptext[i] + key ) % 26);. Specifically with % 26. It certainly looks exactly like the problem set:
More formally, if p is some plaintext (i.e., an unencrypted message),
pi is the ith character in p, and k is a secret key (i.e., a
non-negative integer), then each letter, ci, in the ciphertext, c, is
computed as
ci = (pi + k) % 26
wherein % 26 here means “remainder when dividing by 26.”
But, the pset goes on to say:
think of A (or a) as 0, B (or b) as 1, …, H (or h) as 7, I (or i) as
8, …, and Z (or z) as 25.
The problem is that the character ptext[i] is the ascii value of the letter, not the "alphabet index".
Perhaps review the spoiler in the pseudocode section of the Lab, particularly #5:
Iterate over each character of the plaintext:
If it is an uppercase letter, rotate it, preserving case, then print out the rotated character
If it is a lowercase letter, rotate it, preserving case, then print out the rotated character
If it is neither, print out the character as is
You may find this walkthrough (from an earlier iteration of the course) helpful.

Related

Why the function does not work when there are two zeros in the function?

I'm trying to write code that counts even digits (a typical beginner task)
What changes do I need to make in the code to get 2, for example, from the number 0011?
Is there a simple solution without additional libraries and complex loops?
#include <stdio.h>
int evensDigitsCount(int number);
int main()
{
int res = evensDigitsCount(0011);
printf("Counter: %d\n",res);
return 0;
}
int evensDigitsCount(int number)
{
int rem = 0;
int count = 0;
do{
rem = number % 10;
if(rem % 2 == 0 )
count++;
number = number / 10;
}while(number != 0);
return count;
}
“0011” is not a number. It is a numeral, which is a string of characters that represents a number.
In common human notation, “0011” is in decimal and represents the number eleven. However, in C source code, numerals starting with “0” (but not “0x” or “0X”) use octal, so “0011” represents the number nine.
Calling evensDigitsCount(0011) gives the number parameter of evensDigitsCount the value nine. It is just that abstract mathematical entity of nine; it does not have any digits or other characters representing it. (It is represented inside the computer with a string of bits, but that does not matter here, because the C source code you show operates on its value, not the bits that represent it.)
When the program executes rem = number % 10, number has the value nine, and the remainder of nine modulo ten is nine, so rem is set to nine. This is not even, so count++ is not executed.
Then number = number / 10; calculates nine divided by ten, rounded down (since number is positive) to an integer. This produces zero, so number is set to zero, and the loop ends.
To count the digits in a numeral, you must pass the numeral as a string, not a number. You could rewrite evensDigitsCount to have a parameter of const char *numeral, and then you could call it with evensDigitCount("0011"). Then the function could examine each character in the string to check whether it is one of the even digits, “0”, “2”, “4”, “6”, or “8”.
Your code is behaving correctly. 0011 is an octal literal for the decimal value 9, and your code is accurately reporting that, in base-10 (decimal), 9 has no even valued digits (the only digit is 9, and it's odd).
Your problem seems to be that you think 0011 remembers the digits it was typed with. It does not. In every way that matters, typing 0011 is the same as typing 9 in the same spot. If you want to preserve all the digits, including leading zeroes (which don't exist once the code is compiled), you need to work with strings (e.g. "0011"), not ints, and parse the digits as you go, rather than extracting them mathematically.
Alternatively, since you ignore odd digits, your existing code will work if you just shove an odd digit on the left side of any literal passed to it (preventing interpretation as octal and preserving the zeroes you expect to see), but that's only valid for literals you control, you couldn't reliably do it for data generate in other ways (which has no way of knowing how many leading zeroes "count").
Numbers starting with 0 are octal constants. So 0011 is octal representation for decimal 9.
Just leave off the leading zeros if you want decimal.
The other answers provided are all correct, explaining the "octal" interpretation of the digits in your OP.
This OP highlights the "unexpected" results when a beginner's knowledge is still growing. "Why does the compiler treat my values different from what I can clearly see in the source code?"
This suggests an interesting (and, perhaps, educational) digression; What if a program COULD examine its own source code?
Below is an attempt to provide an example of a program that does just that. The program reads lines from its own source code file until it finds "the interesting line", then, after some stepping closer to the interesting bit of that line (remembering that this is 'text'), a version of your function counts the number of even 'digits' until it reaches the end of those ASCII digits (the ')' of the function parameter list.)
The only "additional library" is the used everywhere C string library of functions. And these loops should not be too 'complex' to understand. This program makes use of "pointers to strings", a concept to be mastered early in one's learning.
#include <stdio.h> // FILE and printf()
#include <string.h> // str???() // additional library header
// function definitions ahead of "use" eliminates prototypes (for single sources)
// NB: function now "sees" value as a string, not a translated integer
int evensDigitsCount( char *str ) {
char *dgts = "0123456789", *p = NULL; // some variables
int count = 0;
printf( "Examining str: '%s'\n", str );
// step forward thru string as long as finding ASCII integers
// pointer arithemetic converts ASCII digit
// to index in ascending ASCII string of digits
// If index mod 2 has no remaider, then digit is even
// In C, true has the value 1 (false value is 0)
// Add 1 (or 0) to accumulator
for( ; ( p = strchr( dgts, *str ) ) != NULL; str++ )
count += (p - dgts)%2 == 0;
return count;
}
int main() {
// compiler "knows" this source filename.
// it replaces __FILE__ with the filename as a string
char *fname = __FILE__;
char buf[ 256 ]; // generous?
// to remember where target string located in line buffer (when found)
char *fncCall = NULL;
printf( "Examining file '%s'\n", fname );
// open THIS source file (text) for reading
FILE *ifp = fopen( fname, "r" ); // brevity. omitting checks
// read lines until target string found
while( !fncCall && fgets( buf, sizeof buf, ifp ) )
fncCall = strstr( buf, "= evensDigitsCount(0000121);" );
// NB: For this version, it is the line above
// that will be "found" as the 'target'
// (looking for itself in the text of this source code)
// Alternate processing could find the actual function invocation below
// This is an example of "program introspection" for demonstration purposes
fclose( ifp ); // no longer needed
// target not found... should never happen!, but...
if( !fncCall ) {
printf( "Cannot locate target string\n" );
return -1;
}
printf( "Found target: '%s'\n", fncCall );
// invoke (adapted) version of your function
// passing pointer to one-beyond the open parenthesis
int nEven = evensDigitsCount( strchr( fncCall, '(' ) + 1 );
printf( "Number of even digits found = %d\n", nEven );
return 0;
}
Output: The "broken lines" arise because fgets() leaves the LF at the end of the string buffer.
Examining file '.../StackOver.c' // shortened full name
Found target: '= evensDigitsCount(0000121);" );
'
Examining str: '0000121);" );
'
Number of even digits found = 5 // expected result!
Although this answer departs from your OP somewhat, it does show how you may be able to write a program that sees things your way (when you need to.)

C: How to add char to chars, and when the max char is reached have it loop back to 'a'?

I am creating a simple encryption program.
I am adding chars to chars to create a new char.
As of now the new 'char' is often a represented by a '?'.
My assumption was that the char variable has a max sum and once it was passed it looped back to 0.
assumed logic:
if char a == 1 && char z == 255
then 256 should == a.
This does not apear to be the case.
This snippet adds a char to a char.
It often prints out something like:
for (int i = 0; i < half; ++i) {
halfM1[i] = halfM1[i] + halfP1[i];
halfM2[i] = halfM2[i] + halfP2[(half + i)];
}
printf("\n%s\n", halfM1 );
printf("%s\n", halfM2);
Returns:
a???
3d??
This snippet removes the added char and the strings go back to normal.
for (int i = 0; i < half; ++i) {
halfM1[i] = halfM1[i] - halfP1[i];
halfM2[i] = halfM2[i] - halfP2[(half + i)];
}
printf("\n%s\n", halfM1 );
printf("%s\n", halfM2);
returns:
messagepart1
messagepart2
The code technically works, but I would like the encryption to be in chars.
If question on why 'half' is everywhere.
The message and key are split in half so the first half and second half of message have separate encryption.
First of all, there is no such thing as "wraparound" for common char. A common char is a signed type in x86, and signed integers do not have wraparound. Instead the overflow leads to undefined behaviour. Additionally, the range of chars can be -128 ... 127, or even something
For cryptographic purposes you'd want to use unsigned chars, or even better, raw octets with uint8_t (<stdint.h>).
Second problem is that you're printing with %s. One of the possible 256 resulting characters is \0. If this gets into the resulting string, it will terminate the string prematurely. Instead of using %s, you should output it with fwrite(halfM1, buffer_size, 1, stdout). Of course the problem is that the output is still some binary garbage. For this purposes many Unix encryption programs will write to file, or have an option to output an ASCII-armoured file. A simple ASCII armouring would be to output as hex instead of binary.
The third is that there is an operation that is much better than addition/subtraction for cryptographic purposes: XOR, or halfM1[i] = halfM1[i] ^ halfP1[i]; - the beauty of which is that it is its own inverse!

Common character to indicate error has occured

Typically in a function that returns an integer, -1 is used to indicate to the user/programmer that a error has occurred in the program. e.g. A program may return -1 instead of the index of where a word starts in a string if the word cannot be found in the string.
So my question is, what should you return from a function that returns a character instead?
In other words, is there a common character that most programmers use like -1 to detect when an error has occurred?
It may be subjective to the scenario of course so lets say you created a program that converts a digit into its corresponding character:
char digitToCh (int digit)
{
if ( digit < 0 ) // If digit is negative, return ?
return '?';
int n = intLen (digit);
if ( n > 1 )
digit /= power (10, n - 1);
return (char) (((int) '0') + digit);
}
If the digit is negative, what error character code would seem appropriate. This example is quite arbitrary but I'm just trying to make it simpler to express.
No, there is no such reserved character. In fact, it is the absence of such common character that caused character-oriented I/O functions to change their return type to int.
The trick with returning an int is important when you must retain the full range of character return values. In your case, however, only the ten digit characters are valid, so returning character zero '\0' is a valid option:
char digitToCh (int digit) {
if (digit < 0) return '\0';
...
}
You can check the error like this:
char nextDigit = digitToCh(someInt);
if (!nextDigit) {
// The next digit is invalid
}
Make the function return an int instead of a char and also use -1 to indicate an error.
This way it is done by fgetc() for example.
.

Macro directives in C — my code example doesn't work

I want to get the following piece of code to work:
#define READIN(a, b) if(scanf('"#%d"', '"&a"') != 1) { printf("ERROR"); return EXIT_FAILURE; }
int main(void)
{
unsigned int stack_size;
printf("Type in size: ");
READIN(d, stack_size);
}
I don't get how to use directives with the # operator. I want to use the scanf with print ERROR etc. several times, but the "'"#%d"' & '"&a"'" is, I think, completely wrong. Is there any way to get that running? I think a macro is the best solution — or do you disagree?
You should only stringify arguments to the macro, and they must be outside of strings or character constants in the replacement text of the macro. Thus you probably should use:
#define READIN(a, b) do { if (scanf("%" #a, &b) != 1) \
{ fprintf(stderr, "ERROR\n"); return EXIT_FAILURE; } \
} while (0)
int main(void)
{
unsigned int stack_size;
printf("Type in size: ");
READIN(u, stack_size);
printf("You entered %u\n", stack_size);
return(0);
}
There are many changes. The do { ... } while (0) idiom prevents you from getting compilation errors in circumstances such as:
if (i > 10)
READIN(u, j);
else
READIN(u, k);
With your macro, you'd get an unexpected keyword 'else' type of message because the semi-colon after the first READIN() would be an empty statement after the embedded if, so the else could not belong to the visible if or the if inside the macro.
The type of stack_size is unsigned int; the correct format specifier, therefore, is u (d is for a signed int).
And, most importantly, the argument a in the macro is stringized correctly (and string concatenation of adjacent string literals - an extremely useful feature of C89! - takes care of the rest for you. And the argument b in the macro is not embedded in a string either.
The error reporting is done to stderr (the standard stream for reporting errors on), and the message ends with a newline so it will actually appear. I didn't replace return EXIT_FAILURE; with exit(EXIT_FAILURE);, but that would probably be a sensible choice if the macro will be used outside of main(). That assumes that 'terminate on error' is the appropriate behaviour in the first place. It often isn't for interactive programs, but fixing it is a bit harder.
I'm also ignoring my reservations about using scanf() at all; I usually avoid doing so because I find error recovery too hard. I've only been programming in C for about 28 years, and I still find scanf() too hard to control, so I essentially never use it. I typically use fgets() and sscanf() instead. Amongst other merits, I can report on the string that caused the trouble; that's hard to do when scanf() may have gobbled some of it.
My thought with scanf() here is, to only read in positive numbers and no letters. My overall code does create a stack, which the user types in and the type should be only positive, otherwise error. [...] I only wanted to know if there's a better solution to forbid the user to type in something other than positive numbers?
I just tried the code above (with #include <stdlib.h> and #include <stdio.h> added) and entered -2 and got told 4294967294, which isn't what I wanted (the %u format does not reject -2, at least on MacOS X 10.7.2). So, I would go with fgets() and strtoul(), most likely. However, accurately detecting all possible problems with strtoul() is an exercise of some delicacy.
This is the alternative code I came up with:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
int main(void)
{
unsigned int stack_size = 0;
char buffer[4096];
printf("Type in size: ");
if (fgets(buffer, sizeof(buffer), stdin) == 0)
printf("EOF or error detected\n");
else
{
char *eos;
unsigned long u;
size_t len = strlen(buffer);
if (len > 0)
buffer[len - 1] = '\0'; // Zap newline (assuming there is one)
errno = 0;
u = strtoul(buffer, &eos, 10);
if (eos == buffer ||
(u == 0 && errno != 0) ||
(u == ULONG_MAX && errno != 0) ||
(u > UINT_MAX))
{
printf("Oops: one of many problems occurred converting <<%s>> to unsigned integer\n", buffer);
}
else
stack_size = u;
printf("You entered %u\n", stack_size);
}
return(0);
}
The specification of strtoul() is given in ISO/IEC 9899:1999 §7.20.1.4:
¶1 [...]
unsigned long int strtoul(const char * restrict nptr,
char ** restrict endptr, int base);
[...]
¶2 [...] First,
they decompose the input string into three parts: an initial, possibly empty, sequence of
white-space characters (as specified by the isspace function), a subject sequence
resembling an integer represented in some radix determined by the value of base, and a
final string of one or more unrecognized characters, including the terminating null
character of the input string. Then, they attempt to convert the subject sequence to an
integer, and return the result.
¶3 [...]
¶4 The subject sequence is defined as the longest initial subsequence of the input string,
starting with the first non-white-space character, that is of the expected form. The subject
sequence contains no characters if the input string is empty or consists entirely of white
space, or if the first non-white-space character is other than a sign or a permissible letter
or digit.
¶5 If the subject sequence has the expected form and the value of base is zero, the sequence
of characters starting with the first digit is interpreted as an integer constant according to
the rules of 6.4.4.1. If the subject sequence has the expected form and the value of base
is between 2 and 36, it is used as the base for conversion, ascribing to each letter its value
as given above. If the subject sequence begins with a minus sign, the value resulting from
the conversion is negated (in the return type). A pointer to the final string is stored in the
object pointed to by endptr, provided that endptr is not a null pointer.
¶6 [...]
¶7 If the subject sequence is empty or does not have the expected form, no conversion is
performed; the value of nptr is stored in the object pointed to by endptr, provided
that endptr is not a null pointer.
Returns
¶8 The strtol, strtoll, strtoul, and strtoull functions return the converted
value, if any. If no conversion could be performed, zero is returned. If the correct value
is outside the range of representable values, LONG_MIN, LONG_MAX, LLONG_MIN,
LLONG_MAX, ULONG_MAX, or ULLONG_MAX is returned (according to the return type
and sign of the value, if any), and the value of the macro ERANGE is stored in errno.
The error I got was from a 64-bit compilation where -2 was converted to a 64-bit unsigned long, and that was outside the range acceptable to a 32-bit unsigned int (the failing condition was u > UINT_MAX). When I recompiled in 32-bit mode (so sizeof(unsigned int) == sizeof(unsigned long)), then the value -2 was accepted again, interpreted as 4294967294 again. So, even this is not delicate enough...you probably have to do a manual skip of leading blanks and reject a negative sign (and maybe a positive sign too; you'd also need to #include <ctype.h> too):
char *bos = buffer;
while (isspace(*bos))
bos++;
if (!isdigit(*bos))
...error - not a digit...
char *eos;
unsigned long u;
size_t len = strlen(bos);
if (len > 0)
bos[len - 1] = '\0'; // Zap newline (assuming there is one)
errno = 0;
u = strtoul(bos, &eos, 10);
if (eos == bos ||
(u == 0 && errno != 0) ||
(u == ULONG_MAX && errno != 0) ||
(u > UINT_MAX))
{
printf("Oops: one of many problems occurred converting <<%s>> to unsigned integer\n", buffer);
}
As I said, the whole process is rather non-trivial.
(Looking at it again, I'm not sure whether the u == 0 && errno != 0 clause would ever catch any errors...maybe not because the eos == buffer (or eos == bos) condition catches the case there's nothing to convert at all.)
You are incorrectly encasing your macro argument(s), it should look like:
#define READIN(a, b) if(scanf("%"#a, &b) != 1) { printf("ERROR"); return EXIT_FAILURE; }
you use of the stringify operator was also incorrect, it must directly prefix the argument name.
In short, use "%"#a, not '"#%d"', and &b, not '"&a"'.
as a side note, for longish macro's like those, it helps to make them multi-line using \, this keeps them readable:
#define READIN(a, b) \
if(scanf("%"#a, &b) != 1) \
{ \
printf("ERROR"); \
return EXIT_FAILURE; \
}
When doing something like this, one should preferably use a function, something along the lines of this should work:
inline int readIn(char* szFormat, void* pDst)
{
if(scanf(szFormat,pDst) != 1)
{
puts("Error");
return 0;
}
return 1;
}
invoking it would be like so:
if(!readIn("%d",&stack_size))
return EXIT_FAILURE;
scanf(3) takes a const char * as a first argument. You are passing '"..."', which is not a C "string". C strings are written with the " double quotes. The ' single quotes are for individual characters: 'a' or '\n' etc.
Placing a return statement inside a C preprocessor macro is usually considered very poor form. I've seen goto error; coded inside preprocessor macros before for repetitive error handling code when storing formatted data to and reading data from a file or kernel interface, but these are definitely exceptional circumstances. You would detest debugging this in six months time. Trust me. Do not hide goto, return, break, continue, inside C preprocessor macros. if is alright so long as it is entirely contained within the macro.
Also, please get in the habit of writing your printf(3) statements like this:
printf("%s", "ERROR");
Format string vulnerabilities are exceedingly easy to write. Your code does not contain any such vulnerability now, but trust me, at some point in the future those strings are inevitably modified to include some user-supplied content, and putting in an explicit format string now will help prevent these in the future. At least you'll think about it in the future if you see this.
It is considered polite to wrap your multi-line macros in do { } while (0) blocks.
Finally, the stringification is not quite done correctly; try this instead:
#define READIN(A, B) do { if (scanf("%" #A, B) != 1) { \
/* error handling */ \
} else { \
/* success case */ \
} } while(0)
Edit: I feel I should re-iterate akappa's advice: Use a function instead. You get better type checking, better backtraces when something goes wrong, and it is far easier to work with. Functions are good.

Why do I get this unexpected result using atoi() in C?

I don't understand the results of the following C code.
main()
{
char s[] = "AAA";
advanceString(s);
}
void advanceString(p[3])
{
int val = atoi(p);
printf("The atoi val is %d\n",val);
}
Here the atoi value is shown as 0, but I could not figure out the exact reason.
As per my understanding, it should be the summation of decimal equivalent of each values in the array? Please correct me if I am wrong.
atoi() converts a string representation of an integer into its value. It will not convert arbitrary characters into their decimal value. For instance:
int main(void)
{
const char *string="12345";
printf("The value of %s is %d\n", string, atoi(string));
return 0;
}
There's nothing in the standard C library that will convert "A" to 65 or "Z" to 90, you'd need to write that yourself, specifically for whatever charset you're expecting as input.
Now that you know what atoi() does, please don't use it to deal with numeric input in whatever you come up with. You really should deal with input not being what you expect. Hmm, what happens when I enter 65 instead of A? Teachers love to break things.
atoi() doesn't do any error checking whatsoever, which makes anything relying on it to convert arbitrary input fragile, at best. Instead, use strtol() (POSIX centric example):
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(void)
{
static const char *input ="123abc";
char *garbage = NULL;
long value = 0;
errno = 0;
value = strtol(input, &garbage, 0);
switch (errno) {
case ERANGE:
printf("The data could not be represented.\n");
return 1;
// host-specific (GNU/Linux in my case)
case EINVAL:
printf("Unsupported base / radix.\n");
return 1;
}
printf("The value is %ld, leftover garbage in the string is %s\n",
// Again, host-specific, avoid trying to print NULL.
value, garbage == NULL ? "N/A" : garbage);
return 0;
}
When run, this gives:
The value is 123, leftover garbage in
the string is abc
If you don't care about saving / examining the garbage, you can set the second argument to NULL. There is no need to free(garbage). Also note, if you pass 0 as the third argument, it's assumed the input is the desired value of a decimal, hex or octal representation. If you need a radix of 10, use 10 - it will fail if the input is not as you expect.
You'd also check the return value for the maximum and minimum value a long int can handle. However, if either are returned to indicate an error, errno is set. An exercise for the reader is to change *input from 123abc to abc123.
It's important to check the return, as your example shows what happens if you don't. AbcDeFg is not a string representation of an integer, and you need to deal with that in your function.
For your implementation, the most basic advice I can give you would be a series of switches, something like:
// signed, since a return value of 0 is acceptable (NULL), -1
// means failure
int ascii_to_ascii_val(const char *in)
{
switch(in) {
// 64 other cases before 'A'
case 'A':
return 65;
// keep going from here
default:
return -1; // failure
}
.. then just run that in a loop.
Or, pre-populate a dictionary that a lookup function could scope (better). You wouldn't need hashes, just a key -> value store since you know what it's going to contain in advance, where the standard ASCII characters are keys, and their corresponding identifiers are values.
It tries to convert the string into an integer. Since AAA cannot be converted into an integer the value is 0. Try giving it 42 or something.
If no valid conversion could be
performed, a zero value is returned.
See http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/
Read atoi() as a to i (ASCII to integer).
atoi() converts a string representing a decimal number, to integer.
char s[] = "42";
int num = atoi(s); //The value of num is 42.
atoi expects its argument to be a string representation of a decimal (base-10) integer constant; AAA is not a valid decimal integer constant, so atoi returns 0 because it has no other way to indicate that the input is invalid.
Note that atoi will convert up to the first character that isn't part of a valid integer constant; in other words, "123" and "123w" will both be converted to 123.
Like everyone else is saying, don't use atoi; use strtol instead.

Resources