Simple unit converter in C - c

I purchased "A Book on C" for my procedural programming class and I was going through some of the exercises. Chapter 2 Exercise 9 is about designing a unit converter that can work with ounces, pounds, grams, and kilograms.
The code I've written works, but I really think it could be done much cleaner. Using nested if statements seems like a messy way to go about this.
Also, one problem I noticed was that if a char or string is given to scanf() on line 27, it will persist and then be passed to the scanf() on line 95. For example, if you enter "y" as the value to convert, the program will goto beginning without allowing the user to answer "Would you like to perform additional conversions?" How can I go about fixing this so that if a NaN is input it is discarded?
My code can be located at:
http://pastebin.com/4tST0i7T

One way to clean up the if structure would be to convert the value from the "fromUnit" to a common value and then convert it to the "toUnit". It simplifies the structure by leaving only two if structures around. (It also scales better.) So, it would be something more like:
if (!strcmp(fromUnit, "pound")) {
tempval = input / 16;
} else if (!strcmp(fromUnit, "gram") == 0) {
tempval = input * OUNCESTOGRAMS;
}
if (!strcmp(toUnit, "pound")) {
output = tempval * 16;
} else if (!strcmp(toUnit, "gram")) {
output = tempval / OUNCESTOGRAMS;
}
Granted, that math isn't correct, it's just there for the example. You would just have to (1) pick the temporary unit that you wanted to use (2) convert from the input unit to that unit and (3) convert from the temporary unit to the output unit.
And as someone else mentioned, gets() is definitely the way to go.

I would do it something like this:
#include <stdio.h>
typedef struct _unit {
char * name;
float grams;
} unit;
unit units[] = {
{"gram", 1.0},
{"kilogram", 1000.0},
{"pound", 500.0},
{"ounce", 28.3495231}
};
unit * search_unit(char * name)
{
int i;
for (i = 0; i < (sizeof(units) / sizeof(unit)); i++)
{
printf("%d %s\n", i, units[i].name);
if (0 == strcmp(units[i].name, name))
{
return & units[i];
}
}
return NULL;
}
int main() {
char line[10];
char unitname[10];
int number;
unit * found_unit;
while (1)
{
fgets(line, sizeof(line), stdin);
if (1 == sscanf(line, "%d", &number))
{
break;
}
printf("not a number\n");
}
while (1)
{
fgets(line, sizeof(line), stdin);
sscanf(line, "%s\n", unitname);
found_unit = search_unit(unitname);
if (found_unit)
{
printf("%d %s is %f grams\n", number, unitname, found_unit->grams * number);
break;
}
printf("unknown unit\n");
}
}
Store your data in some data structure, instead of in the code.
First read a line of text, then check whether it is a number.
When reading from stdin, take the size of the buffer into account.
Use loops instead of goto's.
Use some common unit, grams for example, to calculate anything to anything.

The most reliable way is to read input string using fgets() function, check if it contains digit using isdigit() (all characters in string) and then convert it to numeric value using atoi().
BTW, the last two operations can be replaced by strtol().

Related

How can I make alphabets entered (through scanf) interpret as integers the way it's defined in enum. Please refer program below

I am trying to make a C program for converting a given number in say base x, to base y. I chose to narrow it down upto base 20 (i.e. Base 2 to 20). When it comes to scanning a hexadecimal number (includes ABCDEF too, right?) for example, I am stuck. Please look at my program below:
/* NOTE: This program uses two step approach to convert a given number in any base (except base 10, in which case we will use only "toany()") to any other base*/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
int inum,ibase, obase;
int todec(); //function to convert to decimal from any base
int toany(int); //function to convert from decimal to any base
int exp(int,int); //used in other function
void main()
{
int num,choice;
char strr[100];
enum{A=10,B,C,D,E,F,G,H,I,J};
here:
printf("Enter the base (RADIX) of your number: ");
scanf("%d",&ibase);
printf("Enter the number in base %d: ",ibase);
scanf("%s",strr);
printf("Enter the base in which you want the output: ");
scanf("%d",&obase);
inum=atoi(strr);
switch(obase)
{
case 10:
num=todec();
printf("Output in base 10: %d\n",num);
break;
default:
if(ibase==10)
num=toany(inum);
else
num=toany(todec());
printf("Output in base %d: %d\n",obase,num);
break;
}
printf("WANNA DO IT AGAIN? If yes, Press 1 else press 0:");
scanf("%d",&choice);
if(choice==1)
goto here;
else
exit(0);
getch();
}
int exp(int p, int q)
{
int i,result=1;
for(i=1;i<=q;i++)
{
result=result*p;
}
return(result);
}
int todec()
{
int inumarr[100],dupnum=inum,i=0,counter,decnum=0;
while(dupnum!=0)
{
inumarr[i]=dupnum%10;
dupnum/=10;
i++;
}
for(counter=0;counter<i;counter++)
{
decnum=decnum+inumarr[counter]*exp(ibase, counter);
}
return(decnum);
}
int toany(int num)
{
int outnumarr[100],i=0,q,result=0;
while(num!=0)
{
outnumarr[i]=num%obase;
num=num/obase;
i++;
}
for(q=0;q<i;q++)
{
result=result+outnumarr[q]*exp(10,q);
}
return(result);
}
Thanks for reading! Now, I know it's definitely a mess where I tried to scan as a string and then applied atoi function on a string that might contain alphabets (like "19E" in base 16...which is 414 in base 10). So, I am looking for a decent solution which will allow the user of this program to enter any number like "19E" and my program will interpret that 'E' as 14 (AS DEFINED IN MY ENUM) and also a decent way to show an output of numbers like "19E" would be great.
Disclaimer: The code I've put into this answer is untested. I'm currently on a mobile device, so even compiling it is less convenient than usual. I will strive to include enough details for you to find your way past any (possible) errors, please point them out though... On another day I'll polish this post off by adding more checks (described at the end) and explain serialisation as well as deserialisation. As it stands, however, it seems you're just asking about deserialisation, so without further adeau:
Build a lookup table of some description containing each character from your base. For characters then you can (usually) get away with using string operations. For example:
unsigned char hex_digit[] = "00112233445566778899AaBbCcDdEeFf";
If you use strchr and some pointer arithmetic you can now find the offset of a character, divide by two to reduce it to a value within 0 .. 15, or modulo by two to discriminate between lowercase and uppercase.
You can devise any base like this, with a generic loop parsing the input to facilitate larger values...
size_t to_native_uimax(char *str, unsigned char *base, uintmax_t *value) {
size_t x, base_size = strlen(str);
uintmax_t v = 0;
for (x = 0; str[x]; x++) {
unsigned char *c = strchr(base, str[x]);
if (!c) break;
v *= base_size / 2;
v += (c - base) / 2;
}
*value = v;
return x;
}
Signage is a bit trickier to handle, but because we only need to handle the sign at the start of the string we can reuse the code above.
size_t to_native_imax(unsigned char *str, unsigned char *base, intmax_t *value) {
uintmax_t v = 0;
size_t x = to_native_uimax(str + !!strchr("-+", *str), base, &v);
*value = *str == '-' ? -(intmax_t)v : v;
return x;
}
Also note that this code isn't strictly portable; if it's possible that this might be deployed to a system that has negative zeros or signals on overflow more checks should precede the (intmax_t) conversion.

Trying to find frequency of certain characters in a string but the results are very far off

I am trying to write a program which calculates and prints the GC content of a string of DNA(which is input through a txt file). That is, the percentage of G's and C's in a string of DNA. Here is my function for the GC percentage:
void updateGCCount(char s[], int *gc, int *at) {
char c[MAXLENGTH];
int i,GCcount,ATcount;
float len,GCpercentage;
GCcount=0;
ATcount=0;
for(i=0;c[i]!='\0';++i)
{
if(c[i]=='G' || c[i]=='C')
{
++GCcount;
*gc=GCcount;
}
if(c[i]=='A' || c[i]=='T')
{
++ATcount;
*at=ATcount;
}
}
strcpy(c,s);
len=strlen(c);
GCpercentage=*gc/len;
printf("GC-content: %.2f\n",GCpercentage);
}
This is my function definition, and the part which is supposed to correctly print the GC percentage is what I am not sure about. Below is my main program which utilizes the input text file.
#include "genomics.h"
int main(){
char s[MAXLENGTH];
int gc, at;
scanf("%s",s);
printf("Sequence : %s\n",s);
updateGCCount(s, &gc, &at);
return 0;
}
Any help or advice on why I am not getting a correct value for the GCpercentage would be great. Thank you in advance
You're doing your tests on char array "c":
char c[MAXLENGTH];
...
for(i=0;c[i]!='\0';++i)
{
if(c[i]=='G' || c[i]=='C')
{
++GCcount;
*gc=GCcount;
}
if(c[i]=='A' || c[i]=='T')
{
++ATcount;
*at=ATcount;
}
}
If should be on s, the array that you passed in. The c array is probably superflous, you should be able to get the length from s as well
c is not initialize, so *gc and *at are not updated at all and they contain garbage..
here you should use s instead of c
for(i=0;c[i]!='\0';++i)
{
if(c[i]=='G' || c[i]=='C')
{
++GCcount;
*gc=GCcount;
}
if(c[i]=='A' || c[i]=='T')
{
++ATcount;
*at=ATcount;
}
}
That's a strongly un-idiomatic program. Consider the following.
#include <stdio.h>
#include <stdlib.h> /* for exit(3) */
float count_gc(const char* s)
{
You have no need to pass information back via variables passed in by reference. Functions return values -- typically 'the answer'.
You're simply scanning the content of the argument string s, so there's no need to copy it anywhere.
As others have pointed out, you were scanning the contents of the array c[] before you copied anything in to it -- you were counting 'G' and 'C' in a (probably large) random block of memory. Keeping things simple avoids mistakes like that.
int nvalid = 0;
int gccount = 0;
float result;
for (; *s != '\0'; s++) {
Although the for loop you wrote isn't wrong, it's somewhat un-idiomatic. Here, we examine the character pointed to by the pointer s, and then increment the pointer, until we find ourselves pointing at the \0 that terminates the string. Yes, this means we 'lose' the initial value of the argument, but we don't need it after the loop, so that doesn't matter.
switch (*s) {
A switch is a more natural construction here. You're looking for a small set of possible values that *s (that is, the character the pointer is currently pointing at) may have.
case 'G':
case 'C':
nvalid++;
gccount++;
break;
case 'A':
case 'T':
nvalid++;
break;
default:
/* unexpected character -- ignore it */
break;
Every switch statement should have a default clause -- one should always think of what's supposed to happen if none of the case clauses match. In this case, we just ignore this character.
}
}
if (nvalid == 0) {
fprintf(stderr, "No valid letters found!\n");
result = 0.0;
} else {
/* Multiply by 1.0 to convert integer gccount to a float */
result = 1.0*gccount / nvalid;
}
return result;
We return the result to the caller rather than printing it out inside the function. Functions shouldn't 'chatter', but leave all of the I/O in one place, typically leaving the main function (or something higher up) to look after that.
}
int main(int argc, char** argv)
{
if (argc != 2) {
/* Give the user a hint on how to call the program */
fprintf(stderr, "Usage: gcat <string>\n");
exit(1);
}
printf("Sequence GC-content = %g\n", count_gc(argv[1]));
}
I run that with:
% cc -o gcat gcat.c
% ./gcat "GCAT ATx foo"
Sequence GC-content = 0.333333
%
With C, it's very easy to tie yourself in knots, very quickly. Aim for simplicity always.

Conventional coding for validating inputs in C programming

When validating inputs from a user and doing it through functions in C programming, will you have a lot if if statements that checks 1 or 0 that is returned from the validating functions?
If you don't understand what I mean, then below is code I typed strictly as an example. It's definitely not being used anywhere else.
#include <stdio.h>
int checkIfZero(int x){
int result = 1;
if (x ==0){
printf ("You typed in zero for your age. Try again.\n\n");
result = 0;
}
return result;
}
int checkUpper(char x){
int result = 1;
if (x > 96){
printf("Iniitial is not a uppercase. Try again\n\n");
result =0;
}
return result;
}
int main(int argc, const char * argv[])
{
int age;
char initial;
int correct = 0;
do {
int counter; // holds returned result of first function
int counter2; // holds returned result of the second function
printf("Please type your age and the initial of your first name in Uppercase\n");
scanf("%d %c", &age, &initial);
counter = checkIfZero(age);
if(!counter){
continue;
}
counter2 = checkUpper(initial);
if (!counter2){
continue;
}
correct = 1;
printf("Correct\n");
} while (correct==0);
return 0;
}
If you notice, I have 2 functions that validate the inputs. Later, I have to create different variables that either will have a 1 or 0 form what these functions return and check them using if statements.
Now let's say I create more like 10 of validating functions
Does that mean I have to create 10 different variables to catch the returned result of the functions and then type 10 if statements?
I'm okay with that if that's how people usually do it, but is that the case?
You don't have to place the result in a variable:
counter = checkIfZero(numSiblings);
if(!counter){
continue;
Can become:
if (!checkIfZero(numSiblings))
continue;
Define a standard of how it works, and stick to it.
But don't mix up validation ("Is the value OK?") with error message output ("fprintf(...)"). If you sometime later want to, say, check a set of three variables and give a single error message ("Illegal name" after checking given, middle, and last name) this will get in the way. Make sure you can redefine messages (i.e., for your future Greek version of the program, or to reuse the "is this a valid UTF-8 string" validation for different input data; think about combining tests, like UTF-8 and only letters) and that the error output stream can be redirected.
Perhaps you should look around at largeish open source projects, particularly ones that have to validate varied user input. You should be able to find a framework that you can, er, steal.

Translate string to number

I am looking for a way to take a string and check 3 possibilities.
Digit and thus converts it to a signed int (not a long)
Is a symbolic representation previously defined at runtime, and converts it to a signed int
Neither
The "symbolic representation" will be basically like an associative array that starts at 0 elements and expands as more symbols are added. For example lets say for instance that C had associative arrays (I wish) with this peusdocode:
symbol_array['q'] = 3;
symbol_array['five'] = 5;
symbol_array['negfive'] = -5;
symbol_array['random294'] = 28;
signed int i;
string = get_from_input();
if(!(i = convert_to_int(string))) {
if(!(i = translate_from_symbol(string))) {
printf("Invalid symbol or integer\n");
exit(1);
}
}
printf("Your number: %d\n, i);
The idea being if they entered "5" it would convert it to 5 via convert_to_int, and if they entered "five" it would convert it to 5 via translate_from_symbol. As what I feel may be hardest is if they entered "random294" it wouldn't convert it to 294, but to 28. If they entered "foo" then it would exit(1).
My general questions are these: (Instead of making multiple posts)
When making convert_to_int I know I shouldn't use atoi because it doesn't fail right. Some people say to use strtol but it seems tedious to convert it back to a non-long int. The simplistic (read: shortest) way I've found is using sscanf:
int i;
if ((sscanf(string, "%d", &i)) == 1){
return i;
}
However, some people look down on that even. What is a better method if not sscanf or converting strtol?
Secondly, how can I not only return an integer but also know if it found one. For example if the user entered "0" then it would return 0, thus setting off my FALSE in my if statement. I had considered using -1 if not found but since I am returning signed int's then this also suffers from the same problem. In PHP I know for example with strpos they use === FALSE
Finally, is there any short code that emulates associate arrays and/or lets me push elements on to the array in runtime?
First, you might want to revise your syntax and set the keyword apart from the operand, i.e. "neg five" instead of "negfive". Otherwise your symbol lookup for the keywords has to consider every prefix. ("random294" might be okay if your keywords aren't allowed to have digits in them.)
Sure, sscanf tells you whether you found a decimal in the return value and writes that decimal to a separate int, which is nice, but you'll have to watch out for trailing characters by checking that the number of characters read equals the length of your string with the %n format. Otherwise, sscanf will consider 5x as legal decimal number. strtol also returns a pointer to the location after the parsed decimal number, but it relies too much on checking err for my taste.
The fact that strtol uses long integers shouldn't be an issue. If the input doesn't fit into an int, return INT_MAX or INT_MIN or issue an error.
You can also easily write a wrapper function around sscanf or strtol that suits your needs better. (I know I'd like a function that returns true on success and stores the integer via a pointer argument, sscanf style, where success means: no trailing non-digit characters.)
Finally, about the associative arrays: There is no short code, at least not in C. You'll have to implement your own hash map or use a library. As a first draft, I'd use a linear list of strings and check them one by one. This is a very naive approach, but easy to implement. I assume that you don't start out with a lot of symbols, and you're not doing a lot of checks, so speed shouldn't be an issue. (You can sort the array and use binary search to speed it up, but you'd have to re-sort after every insertion.) Once you have the logic of your program working, you can start thinking about hash maps.
Something like this should do your job:
#include <stdio.h>
#include <string.h>
struct StringToLongLookUp {
char *str;
char *num;
};
struct StringToLongLookUp table[] =
{
{ "q" , "3" },
{ "five" , "5" },
{ "negfive" , "-5" },
{ "random294", "28" }
};
int translate_from_symbol(char **str)
{
int i;
for(i = 0; i < (sizeof(table) / sizeof(struct StringToLongLookUp)); i++)
{
if(strcmp(*str, table[i].str) == 0)
{
*str = table[i].num;
return 1; // TRUE
}
}
return 0; // FALSE
}
int main()
{
char buf[100];
char *in = buf;
char *out;
int val;
scanf("%s", in);
translate_from_symbol(&in);
val = strtol(in, &out, 10);
if (in != out)
{
printf("\nValue = %d\n", val);
}
else
{
printf("\nValue Invalid\n");
}
}
Of course, you get a long, but converting that to int shouldn't be an issue as mentioned above.

Getting the number of digits of an integer

bool isValidId(int* id)
{
if(log10(*id) != 6)
{
return false;
}
return true;
}
printf("Enter ID: ");
gets(input);
c.id = atoi(input);
validID= isValidId(c.id);
if(!validID)
{
printf("Invalid ID format -(Use example 123456 format). \n");
}
This is how it looks now.I ask the user to enter an ID and check it if is valid with the isValidId method but my program is crashing when I enter an ID. Please help! Thanks
return *id >= 100000 && *id < 1000000;
I think this may be a good solution, both easy to read and efficient.
There is no need to acquire its length if you just want to judge if it is a valid id
Program crashes because the parameter of isValidId is pointer to int, not int, so
validID = isValidId(c.id);
should be
validID = isValidId(&c.id);
First of all, I don't see any reason to pass a pointer to isValidId function. You can pass an integer and calculate the number of digits.
bool isValidId(int id) {
// count digits here
}
Now there are at least two ways to calculate the number of digits. First one is to use log10. The number of digits in a 10-base integer n is (int)(log10(n) + 1). You will need to import math.h to use log10. You may check whether n <= 0 before calling log10.
The second way is to loop through n.
int count = 0;
while (n > 0) {
count++;
n /= 10;
}
You've declared isValidId to take a pointer to an int, but you're passing it a plain int; in this case, there's no reason to use a pointer, so you'd be better off changing isValidId to use a regular int.
NEVER NEVER NEVER NEVER NEVER USE GETS -- IT WILL INTRODUCE A POINT OF FAILURE/MAJOR SECURITY HOLE IN YOUR CODE. Use fgets(input, sizeof input, stdin) instead.
How is input declared? Is it large enough to hold as many digits as int will allow, plus a sign, plus a 0 terminator?
log10 returns a double, not an int. To properly count digits with log10, you will need to write something like (int)floor(log10(id)) + 1.
You can simplify your isValidId function a little:
bool isValidId(int id)
{
return (int) floor(log10(id)) + 1 == 6;
}
The Boolean data type is a latecomer to the C language (introduced in C99), so a lot of us older types tend to avoid using Boolean constants in our code.
I've not done C for eons however try something like this
bool isValidId(int* id)
{
char str[15];
sprintf(str, "%d", id)
if(strlen(str) != 6)
{
return false;
}
return true;
}
It's way easier like this:
#include <math.h>
bool isValidId(int *id)
{
return (int)log10(*id) == 6;
}

Resources