C - Loading from file with fgets and sscanf - c

In a function of my program I am trying to load data from a file into this struct array:
/* database struct */
typedef struct node {
char name[MAX];
char address[MAX];
long int number;
}record_type;
record_type record[100];
The function is as follows:
/* load database from disk */
void load_database() {
char line[128];
/* Set up database */
database = fopen("database.txt", "r+w+a+");
if(database == NULL) {
printf("\n\tWARNING: No database found.");
exit(1);
}
/* Get database file from disk */
while(fgets(line, sizeof(line), database) != NULL) {
sscanf(line, "%s %s %lu", record[rec_num].name,
record[rec_num].address, &record[rec_num].number);
/* keeps track of array size */
rec_num++;
}
}
The issue I am having is inconsistencies with sscanf. If I include first and last name I cannot put a space between them or it places the first name in name[] and the last name in address[].
Here is a sample of the data I am trying to input from:
1. Name: james manes Address: 220 test addr Number: 5558889999
I need to get the "james manes" into the name[] field, 220 test addr into the address[] field and 5558889999 into the number field of the struct. Is this possible at all?
Is there a more efficient way of managing this type of input?

scanf("%s"... parses a whitespace delimited string in your input, so if you have spaces in the strings you want to parse, it won't work.
While you could use regexes to get what you want, since you use fixed strings as your markers, you could instead use strstr to pull out your strings:
while(fgets(line, sizeof(line), database) != NULL) {
char *Name = strstr(line, "Name:");
char *Address = strstr(line, "Address:");
char *Number = strstr(line, "Number:");
if (Name && Address && Number) {
Name += strlen("Name:");
*Address = '\0';
Address += strlen("Address");
*Number = '\0';
Number += strlen("Number:");
strcpy(record[rec_num].name, Name);
strcpy(record[rec_num].address, Address);
sscanf(Number, "%lu", &record[rec_num].number);
rec_num++; } }
Note that this will also pull in all the whitespace around the name and address -- you can trim off leading and trailing whitespace if you want it cleaner.

First of all, you might want to take another look at http://www.cplusplus.com/reference/cstdio/fgets/. Here you will see that the str argument is a pointer to a buffer (which you provided correctly) and then num is the amount of bytes you want to read max, which you did not provide correctly.
The problem with the amount of bytes passed to fgets in you piece of code is the incorrect use of the sizeof operator. The sizeof operator 'returns', as you probably know, the size of the give type. The type you are passing to sizeof is a pointer type (since an array in C for 99% the same as a pointer). The size of a pointer depends on the system you are running on (32 bits on Intel x86, 64bits on AMD64, 16bits on ATmega AVR, etc). So lets asume that you have a 64 bit machine, you will allow fgets to 'get' 64 bits (i.e. 8 bytes) of data, which is not what you want. What would be the correct statement then?
while(fgets(line, sizeof(*line)*128, database) != NULL) {
...
What I'm doing here is dereferencing the char pointer to a char and multipling by the size of this array.
Then, secondly, your question about if this is possible: yes it is. I would like to ask a question myself now too. Is it necessary to do this in C (i.e. platform does not support anything different, learning purposes, etc) or can you also implement this in C#, Java, Python. If so I highly suggest you do.
And last but not least you are asking us about the usefulness of your code. That answer is really simple: no. Not in its current or fixed state. The problem you are having and much more complicated are fixed using a 'real' database (like MySQL) + its API.

Related

How to get the length of a string in c, if it has integers in it

I am familiar with the sizeof operation in C, but when I use it for the string "1234abcd" it only returns 4, which I am assuming is accounting for the last 4 characters.
So how would I get this to be a string of size 8?
specific code is as follows:
FILE *in_file;
in_file = fopen(filename, "r");
if (in_file == NULL) {
printf("File does not exist\n");
return 1;
}
int val_to_inspect = 0;
fscanf(in_file, "%x", &val_to_inspect);
while (val_to_inspect != 0) {
printf("%x", val_to_inspect);
int length = sizeof val_to_inspect;
printf("%d", length);
Again, the string that is being read from the file is "1234abcd", just to clarify.
There're a couple of issues here:
sizeof operator returns the size of the object. In this case it returns the size of val_to_inspect, which is an int.
http://en.cppreference.com/w/cpp/language/sizeof
fscanf reads from a stream and interprets it. You are only scanning an integer ("%x"), not a string.
http://en.cppreference.com/w/cpp/io/c/fscanf
Lastly, if you actually had a nil-terminated string, to get its length you could use strlen().
TL;DR, to get the length of a string, you need to use strlen().
That said, be a little cautious while using sizeof, it operates on the data type. So, if you pass a pointer to it, it will return you the size of the pointer variable, not the length of the string it points to.
In several important ways, only some of which have anything to do with sizeof, you are mistaken about what your code actually does.
FILE *in_file;
in_file = fopen(filename, "r");
if (in_file == NULL)
{
printf("File does not exist\n");
return 1;
}
Kudos for actually checking whether fopen succeeded; lots of people forget to do that when they are starting out in C. However, there are many reasons why fopen might fail; the file not existing is just one of them. Whenever an I/O operation fails, make sure to print strerror(errno) so you know the actual reason. Also, error messages should be sent to stderr, not stdout, and should include the name of the affected file(s) if any. Corrected code looks like
if (in_file == NULL)
{
fprintf(stderr, "Error opening %s: %s\n", filename, strerror(errno));
return 1;
}
(You will need to add includes of string.h and errno.h to the top of the file if they aren't already there.)
int val_to_inspect = 0;
fscanf(in_file,"%x", &val_to_inspect);
This code does not read a string from the file. It skips any leading whitespace and then reads a sequence of hexadecimal digits from the file, stopping as soon as it encounters a non-digit, and immediately converts them to a machine number which is stored in val_to_expect. With the file containing 1234abcd, it will indeed read eight characters from the file, but with other file contents it might read more or fewer.
(Technically, with the %x conversion specifier you should be using an unsigned int, but most implementations will let you get away with using a signed int.)
(When you get more practice in C you will learn that scanf is broken-as-specified and also very difficult to use robustly, but for right now don't worry about that.)
while (val_to_inspect != 0) {
printf("%x", val_to_inspect);
int length = sizeof val_to_inspect;
printf("%d", length);
}
You are not applying sizeof to a string, you are applying it to an int. The size of an int, on your computer, is 4 chars, and that is true no matter what the value is.
Moreover, sizeof applied to an actual C string (that is, a char * variable pointing to a NUL-terminated sequence of characters) does not compute the length of the string. It will instead tell you the size of the pointer to the string, which will be a constant (usually either 4 or 8, depending on the computer) independent of the length of the string. To compute the length of a string, use the library function strlen (declared in string.h).
You will sometimes see clever code apply sizeof to a string literal, which does return a number related to (but not equal to!) its length. Exercise for you: figure out what that number is, and why sizeof does this for string literals but not for strings in general. (Hint: sizeof s will return a number related to s's string length when s was declared as char s[] = "string";, but not when it was declared as char *s = "string";.)
As a final note, it doesn't matter in the grand scheme of things whether you like your opening braces on their own lines or not, but pick one style and stick to it throughout the entire file. Don't put some if opening braces on their own lines and others at the end of the if line.
It's better to create own counter to find the length of "1234abcd" by reading the character by character.
FILE *in_file;
char ch;
int length=0;
in_file = fopen("filename.txt", "r");
if (in_file == NULL)
{
printf("File does not exist\n");
return 1;
}
while (1) {
ch = fgetc(in_file);
printf("%c", ch);
if (ch == EOF)
break;
length++;
}
fclose(in_file);
printf ("\n%d",length);
Everyone, thank you for all the feedback. I realize I made a lot of mistakes with the original post, but im just switching to c from c++, so a lot of the things I'm used to cant really be applied the same way. This is all tremendously helpful, it's good to have a place to go to.
Len=sizeof(your string)/sizeof(char)-1
-1 is eof character null
If you want to get length of any from specific begining index just do Len-index

How to use sscanf to store variables in a line from a file?

I want to scan and store the variables in this line:
11.0.0.0, 255.0.0.0, 10.1.0.1, eth9 as netId, netMask, gateway and interface
Using sscanf(buff1,"%s %s %s %s",netId,netMask,Gateway,Iface); I'm able to store these variables but how can I store these variables when there is a comma(,) as mentioned in the above example?
You have to identify what you want carefully. It is harder than you'd like, but it can be done. The trouble with %s is that it reads up to the first white space character. The comma is not white space, so it will be included in the string scanned by %s, and then there isn't a comma left in the input to match the comma in the format string. So, you need to look for a sequence of 'not commas'. That's a 'scan set'.
if (sscanf(buff1," %[^,], %[^,], %[^,], %s", netId, netMask, Gateway, Iface) != 4)
…data was malformed…
The leading white space in the format skips optional leading spaces in the input string, like %s would skip leading white space.
As Zack notes in a comment, this code does not protect you from buffer overflows. Since you didn't show the definitions of any of the variables, it is not possible to know whether this is an issue or not. If you have:
char buff1[64];
char netId[64];
char netMask[64];
char Gateway[64];
char Iface[64];
then clearly none of the individual fields can be larger than the input buffer and overflow is not possible. OTOH, if the individual fields are smaller than the buffer, Zack is right that you could overflow the buffers.
There are (at least) two ways to avoid that problem. First, assuming each of the target buffers is 16 bytes long (instead of 64 as shown above), then this modified code would be safe:
if (sscanf(buff1," %15[^,], %15[^,], %15[^,], %15s",
netId, netMask, Gateway, Iface) != 4)
…data was malformed…
This could still leave some bytes at the end of the buffer after the Iface element, but is otherwise safe. Note that the size specified in the conversion specification is one less than the size in the data definition; this allows for the null terminator.
The alternative uses a POSIX
sscanf()
feature: the m 'assignment allocation' modifier. In this case, you pass a pointer to a char * to scanf() and it allocates the correct amount of memory:
char *netId = 0;
char *netMask = 0;
char *Gateway = 0;
char *Iface = 0;
if (sscanf(buff1," %m[^,], %m[^,], %m[^,], %ms",
&netId, &netMask, &Gateway, &Iface) != 4)
…data was malformed…
free(netId);
free(netMask);
free(Gateway);
free(Iface);
Note that if a conversion fails, all memory allocated by the m modifier is freed before sscanf() returns. However, it is not guaranteed that if the third allocation fails, the pointers for the first and second allocations are unchanged. Thus, you should not free any of the allocated memory if the overall conversion fails.
You should not do this with sscanf, because you should never use *scanf for anything. There are several reasons for this; the immediately relevant ones are that it's impossible to do error recovery reliably with *scanf, and the %s and %[...] format descriptors can be used without specifying the size of the destination buffer, making them just as dangerous as the infamous gets.
I would personally do this with hand-rolled code of the general form
char *p = buf, *q;
for (q = p; *q && *q != ','; q++) {}
if (!*q) syntax_error();
*q = '\0';
netId = strdup(p);
p = q+1;
while (*p == ' ' || *p == '\t') p++;
for (q = p; *q && *q != ','; q++) {}
if (!*q) syntax_error();
*q = '\0';
netMask = strdup(p);
// etc
There are functions in the standard library (e.g. strsep and strchr) that seem like they can improve on the above, but if you actually try to use them you discover that they don't make your code any shorter or easier to read.
On a POSIX system, another reasonable option is the regex.h interfaces:
// ERROR HANDLING OMITTED FOR BREVITY
// outside the loop
regex_t linere;
regcomp(&linere,
"^([0-9.]+),[ \t]*([0-9.]+),[ \t]*([0-9.]+),[ \t]*([a-zA-Z0-9_]+)$",
REG_EXTENDED);
// inside the loop
regmatch_t rm[5];
regexec(&linere, buf, 5, rm, 0);
netId = malloc(rm[1].rm_eo - rm[1].rm_so + 1);
memcpy(netId, buf + rm[1].rm_so, rm[1].rm_eo - rm[1].rm_so);
netId[rm[1].rm_eo - rm[1].rm_so] = '\0';
// etc
If the parsing job is even a little tiny bit more complicated than this it may be time to reach for lex and yacc.
You need to use %[^,] on your format string to specify the string to copy until ','.
Exactly like:
sscanf(buff1,"%[^,], %[^,], %[^,], %[^,]", netId, netMask, Gateway, Iface);
EDIT1:
Thanks to Jonathan's comment ',' is changed to [^,] in format string.
you simple give the characters you wanna ignore such as comma like this
sscanf(buff1,"%s,%s,%s,%s",netId,netMask,Gateway,Iface);
to ignore them (not read) , scanf and sscanf both look for a exact match of whatever you give within the quotes ,
For Example
if you try to read a String as
char str[20];
scanf("hi%s",str);
you have to enter the input as 'himystring', what gets stored in str will be 'mystring',
Hope that Clears it for you !

Reading strings with spaces from a file

I'm working on a project and I just encountered a really annoying problem. I have a file which stores all the messages that my account received. A message is a data structure defined this way:
typedef struct _message{
char dest[16];
char text[512];
}message;
dest is a string that cannot contain spaces, unlike the other fields.
Strings are acquired using the fgets() function, so dest and text can have "dynamic" length (from 1 character up to length-1 legit characters). Note that I manually remove the newline character after every string is retrieved from stdin.
The "inbox" file uses the following syntax to store messages:
dest
text
So, for example, if I have a message from Marco which says "Hello, how are you?" and another message from Tarma which says "Are you going to the gym today?", my inbox-file would look like this:
Marco
Hello, how are you?
Tarma
Are you going to the gym today?
I would like to read the username from the file and store it in string s1 and then do the same thing for the message and store it in string s2 (and then repeat the operation until EOF), but since text field admits spaces I can't really use fscanf().
I tried using fgets(), but as I said before the size of every string is dynamic. For example if I use fgets(my_file, 16, username) it would end up reading unwanted characters. I just need to read the first string until \n is reached and then read the second string until the next \n is reached, this time including spaces.
Any idea on how can I solve this problem?
#include <stdio.h>
int main(void){
char username[16];
char text[512];
int ch, i;
FILE *my_file = fopen("inbox.txt", "r");
while(1==fscanf(my_file, "%15s%*c", username)){
i=0;
while (i < sizeof(text)-1 && EOF!=(ch=fgetc(my_file))){
if(ch == '\n' && i && text[i-1] == '\n')
break;
text[i++] = ch;
}
text[i] = 0;
printf("user:%s\n", username);
printf("text:\n%s\n", text);
}
fclose(my_file);
return 0;
}
As the length of each string is dynamic then, if I were you, I would read the file first for finding each string's size and then create a dynamic array of strings' length values.
Suppose your file is:
A long time ago
in a galaxy far,
far away....
So the first line length is 15, the second line length is 16 and the third line length is 12.
Then create a dynamic array for storing these values.
Then, while reading strings, pass as the 2nd argument to fgets the corresponding element of the array. Like fgets (string , arrStringLength[i++] , f);.
But in this way you'll have to read your file twice, of course.
You can use fgets() easily enough as long as you're careful. This code seems to work:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAX_MESSAGES = 20 };
typedef struct Message
{
char dest[16];
char text[512];
} Message;
static int read_message(FILE *fp, Message *msg)
{
char line[sizeof(msg->text) + 1];
msg->dest[0] = '\0';
msg->text[0] = '\0';
while (fgets(line, sizeof(line), fp) != 0)
{
//printf("Data: %zu <<%s>>\n", strlen(line), line);
if (line[0] == '\n')
continue;
size_t len = strlen(line);
line[--len] = '\0';
if (msg->dest[0] == '\0')
{
if (len < sizeof(msg->dest))
{
memmove(msg->dest, line, len + 1);
//printf("Name: <<%s>>\n", msg->dest);
}
else
{
fprintf(stderr, "Error: name (%s) too long (%zu vs %zu)\n",
line, len, sizeof(msg->dest)-1);
exit(EXIT_FAILURE);
}
}
else
{
if (len < sizeof(msg->text))
{
memmove(msg->text, line, len + 1);
//printf("Text: <<%s>>\n", msg->dest);
return 0;
}
else
{
fprintf(stderr, "Error: text for %s too long (%zu vs %zu)\n",
msg->dest, len, sizeof(msg->dest)-1);
exit(EXIT_FAILURE);
}
}
}
return EOF;
}
int main(void)
{
Message mbox[MAX_MESSAGES];
int n_msgs;
for (n_msgs = 0; n_msgs < MAX_MESSAGES; n_msgs++)
{
if (read_message(stdin, &mbox[n_msgs]) == EOF)
break;
}
printf("Inbox (%d messages):\n\n", n_msgs);
for (int i = 0; i < n_msgs; i++)
printf("%d: %s\n %s\n\n", i + 1, mbox[i].dest, mbox[i].text);
return 0;
}
The reading code will handle (multiple) empty lines before the first name, between a name and the text, and after the last name. It is slightly unusual in they way it decides whether to store the line just read in the dest or text parts of the message. It uses memmove() because it knows exactly how much data to move, and the data is null terminated. You could replace it with strcpy() if you prefer, but it should be slower (the probably not measurably slower) because strcpy() has to test each byte as it copies, but memmove() does not. I use memmove() because it is always correct; memcpy() could be used here but it only works when you guarantee no overlap. Better safe than sorry; there are plenty of software bugs without risking extras. You can decide whether the error exit is appropriate — it is fine for test code, but not necessarily a good idea in production code. You can decide how to handle '0 messages' vs '1 message' vs '2 messages' etc.
You can easily revise the code to use dynamic memory allocation for the array of messages. It would be easy to read the message into a simple Message variable in main(), and arrange to copy into the dynamic array when you get a complete message. The alternative is to 'risk' over-allocating the array, though that is unlikely to be a major problem (you would not grow the array one entry at a time anyway to avoid quadratic behaviour when the memory has to be moved during each allocation).
If there were multiple fields to be processed for each message (say, date received and date read too), then you'd need to reorganize the code some more, probably with another function.
Note that the code avoids the reserved namespace. A name such as _message is reserved for 'the implementation'. Code such as this is not part of the implementation (of the C compiler and its support system), so you should not create names that start with an underscore. (That over-simplifies the constraint, but only slightly, and is a lot easier to understand than the more nuanced version.)
The code is careful not to write any magic number more than once.
Sample output:
Inbox (2 messages):
1: Marco
How are you?
2: Tarma
Are you going to the gym today?

Conway's Game of Life FileIO

I'm working on learning C and decided to port my Game of Life code over from Java. It doesn't seem too difficult except that the FileIO part. My input file looks something like:
Beehive
5 6
------
--XX--
-X--X-
--XX--
------
Here's the pseduo-code of what I did in Java;
Scanner to open the file,
String line = file.nextLine(),
print the line,
get the second line
Trim and split the firstLine,
String[tokens[0]][tokens[1]],
while(line != NULL) -> string[row][col] = input.charAt(i);
close input,
return string[][]
This is what I have so far in C,
void fileIO() {
FILE *file;
char buffer[BUFFER_SIZE];
file = fopen("INPUT_FILE", "r");
if(file == NULL) {
printf("Cannot open file!");
}
while(fgets(buffer, BUFFER_SIZE, file) != NULL ) {
}
}
I'm not sure how to proceed from here? Can anyone give me a pointer in which way to go from here?
To print a line: puts
puts(buffer);
Note that after fgets, buffer contains the newline character \n, which will be printed too. I guess you want this behavior (not sure how this works in Java).
To trim and split a line: sscanf
int height, width;
...
sscanf(buffer, "%d%d", &height, &width);
To extract a character from a string (instead of input.charAt(i)):
char c = buffer[i];
This is not file I/O; it's just the C syntax for getting a character from a string.
It seems that you have a function in Java that returns a 2-D array (of characters? of strings?), which is dynamically allocated. Java supports recording the width and height in the array object itself, while C doesn't support this. Instead of the 2-D array, you will have to use a struct:
struct MyDataFromFile
{
int height, width;
bool **data;
};
Such data structure is only one possible option; you could use different options:
bool[MAX_HEIGHT][MAX_WIDTH] - convenient if there is maximum height and width
uint64_t *data if you want to use 1 bit for storage, instead of 1 byte - this requires additional bit-fiddling

Best way to do binary arithmetic in C?

I am learning C and writing a simple program that will take 2 string values assumed to each be binary numbers and perform an arithmetic operation according to user selection:
Add the two values,
Subtract input 2 from input 1, or
Multiply the two values.
My implementation assumes each character in the string is a binary bit, e.g. char bin5 = "0101";, but it seems too naive an approach to parse through the string a character at a time. Ideally, I would want to work with the binary values directly.
What is the most efficient way to do this in C? Is there a better way to treat the input as binary values rather than scanf() and get each bit from the string?
I did some research but I didn't find any approach that was obviously better from the perspective of a beginner. Any suggestions would be appreciated!
Advice:
There's not much that's obviously better than marching through the string a character at a time and making sure the user entered only ones and zeros. Keep in mind that even though you could write a really fast assembly routine if you assume everything is 1 or 0, you don't really want to do that. The user could enter anything, and you'd like to be able to tell them if they screwed up or not.
It's true that this seems mind-bogglingly slow compared to the couple cycles it probably takes to add the actual numbers, but does it really matter if you get your answer in a nanosecond or a millisecond? Humans can only detect 30 milliseconds of latency anyway.
Finally, it already takes far longer to get input from the user and write output to the screen than it does to parse the string or add the numbers, so your algorithm is hardly the bottleneck here. Save your fancy optimizations for things that are actually computationally intensive :-).
What you should focus on here is making the task less manpower-intensive. And, it turns out someone already did that for you.
Solution:
Take a look at the strtol() manpage:
long strtol(const char *nptr, char **endptr, int base);
This will let you convert a string (nptr) in any base to a long. It checks errors, too. Sample usage for converting a binary string:
#include <stdlib.h>
char buf[MAX_BUF];
get_some_input(buf);
char *err;
long number = strtol(buf, &err, 2);
if (*err) {
// bad input: try again?
} else {
// number is now a long converted from a valid binary string.
}
Supplying base 2 tells strtol to convert binary literals.
First out I do recommend that you use stuff like strtol as recommended by tgamblin,
it's better to use things that the lib gives to you instead of creating the wheel over and over again.
But since you are learning C I did a little version without strtol,
it's neither fast or safe but I did play a little with the bit manipulation as a example.
int main()
{
unsigned int data = 0;
int i = 0;
char str[] = "1001";
char* pos;
pos = &str[strlen(str)-1];
while(*pos == '0' || *pos == '1')
{
(*pos) -= '0';
data += (*pos) << i;
i++;
pos--;
}
printf("data %d\n", data);
return 0;
}
In order to get the best performance, you need to distinguish between trusted and untrusted input to your functions.
For example, a function like getBinNum() which accepts input from the user should be checked for valid characters and compressed to remove leading zeroes. First, we'll show a general purpose in-place compression function:
// General purpose compression removes leading zeroes.
void compBinNum (char *num) {
char *src, *dst;
// Find first non-'0' and move chars if there are leading '0' chars.
for (src = dst = num; *src == '0'; src++);
if (src != dst) {
while (*src != '\0')
*dst++ = *src++;
*dst = '\0';
}
// Make zero if we removed the last zero.
if (*num == '\0')
strcpy (num, "0");
}
Then provide a checker function that returns either the passed in value, or NULL if it was invalid:
// Check untested number, return NULL if bad.
char *checkBinNum (char *num) {
char *ptr;
// Check for valid number.
for (ptr = num; *ptr == '0'; ptr++)
if ((*ptr != '1') && (*ptr != '0'))
return NULL;
return num;
}
Then the input function itself:
#define MAXBIN 256
// Get number from (untrusted) user, return NULL if bad.
char *getBinNum (char *prompt) {
char *num, *ptr;
// Allocate space for the number.
if ((num = malloc (MAXBIN)) == NULL)
return NULL;
// Get the number from the user.
printf ("%s: ", prompt);
if (fgets (num, MAXBIN, stdin) == NULL) {
free (num);
return NULL;
}
// Remove newline if there.
if (num[strlen (num) - 1] == '\n')
num[strlen (num) - 1] = '\0';
// Check for valid number then compress.
if (checkBinNum (num) == NULL) {
free (num);
return NULL;
}
compBinNum (num);
return num;
}
Other functions to add or multiply should be written to assume the input is already valid since it will have been created by one of the functions in this library. I won't provide the code for them since it's not relevant to the question:
char *addBinNum (char *num1, char *num2) {...}
char *mulBinNum (char *num1, char *num2) {...}
If the user chooses to source their data from somewhere other than getBinNum(), you could allow them to call checkBinNum() to validate it.
If you were really paranoid, you could check every number passed in to your routines and act accordingly (return NULL), but that would require relatively expensive checks that aren't necessary.
Wouldn't it be easier to parse the strings into integers, and then perform your maths on the integers?
I'm assuming this is a school assignment, but i'm upvoting you because you appear to be giving it a good effort.
Assuming that a string is a binary number simply because it consists only of digits from the set {0,1} is dangerous. For example, when your input is "11", the user may have meant eleven in decimal, not three in binary. It is this kind of carelessness that gives rise to horrible bugs. Your input is ambiguously incomplete and you should really request that the user specifies the base too.

Resources