strToInt function convert list of characters to integer in C - c

In C, I need a function that takes an alphanumerical list characters from 0-9 and converts it to an integer.
Code:
int strToInt(char string[])
{
int i, intValue, result = 0;
for (i = 0; string[i] > '0' && string[i] <= '9'; ++i)
{
intValue = string[i] - '0';
result = ???
}
return result;
}
What do I put in the ??? to make it work?

Try this:
result = result * 10 + intValue;
Also:
string[i] > '0'
in the for loop seems nasty - numbers can contain the digit 0, right? You may want to use
string[i] >= '0'
instead, or even better, without reinventing the wheel:
#include <ctype.h>
for (i = 0; isdigit(string[i]); ++i)

Well, your string is in decimal, base 10, and each digit in the string represents a position in a base 10 system. I.e. So you'd want to do
result = result * 10 + intValue;
Remember that '0' is also a digit, so you don't want to omit that one, Use string[i] >= '0'

If you are talking about base 10, you should probably include 0 also as a digit and hence
string[i] >= '0'
in your for loop. and usual place value calculation
result = result*10 + intValue;

Related

How to calculate the frequency of a character in a string in C

I have found code that calculate the frequency of a character in a string, however, all of them are using the same line of code and don't explain what it means. Can someone please enlighten me?
Here is an example:
int c = 0, count[26] = {0}, x;
while (string[c] != '\0') {
/** Considering characters from 'a' to 'z' only and ignoring others. */
if (string[c] >= 'a' && string[c] <= 'z') {
x = string[c] - 'a';
count[x]++;
}
I understand that the loop will iterate through the string until it reaches the end.
I also get the if statement, as that only limits it between a and z.
However, I have no idea what x = string[c] -'a' is doing, why is it subtracting 'a'?
I also don't understand what the purpose of count[26] is.
Here is where I got this program from:
https://www.programmingsimplified.com/c-program-find-characters-frequency
Any help would be great thanks.
TL;DR Is taken advantage of the ASCII table.
The code only accepts characters from a to z:
if (string[c] >= 'a' && string[c] <= 'z')
therefore it creates an array with 26 positions (i.e., count[26]) to store the frequency of those same characters. The following
x = string[c] - 'a';
converts string[c] into an int; fact which can be used to take advantage of the ASCII table.
According to the ASCII table the letters 'a' to 'z' are represented by the int values from 97 to 112, respectively. Therefore, because arrays in C start with 0 we need to shift 97 elements to the left from the value that will be return by string[c], namely:
x = string[c] - 97;
which can be represented by
x = string[c] - 'a';
With this trick if string[c] is 'a' then :
x = 'a' - 'a';
which is converted to x = 97 - 97, then x = 0; Therefore,
count[x]++; is count[0]++;
which increments by 1 the position 0 of the array count, which is "reserved" to the letter 'a'. This same logic applies to all the other letters from 'a' to 'z'.
Bear in mind, however, and quoting Eric Postpischil:
The character codes used in C implementations do not necessarily have
all the letters consecutively. ASCII does and is very common, but not
required by the standard.
Hence, this solution will work if your encoding is ASCII.
count[26] is the frequency table. count[0] is the number of occurrences of a. count[1] is the number of occurrences of b, etc...
Initialize the count array to all zero values
count[26] = {0}
While not at the end of the string. Remember, C strings always end with a null char (\0).
while (string[c] != '\0') {
Evaluate if the character at string[c] is between a and z
if (string[c] >= 'a' && string[c] <= 'z') {
Normalize the ascii value of this character (which will be between 97 and 122) to a value from 0 to 25. a is 97 when evaluated in a math expression.
x = string[c] - 'a';
Using the x value computed above, use that as an index into the count table
Increment whatever value that is in count[x] by 1.
count[x]++;
What's missing from this code sample is the place where c gets incremented by 1 such that string[c] is referencing the next character in the string.
In the ASCII data base, 'a' to 'z' have consecutive numerical code from 0x61 to 0x7A. cf. man ascii.
Hence, if you substract the value of 'a', you get numbers from 0 to 25. This number is an index in count[] table.
count[26] is an array of 26 integers, each one represent the count of a lowercase letter from 'a' to 'z' from within string
count[0] is the counter for 'a', count[1] is the counter for 'b' etc...
x = string[c] - 'a' calculates and assign to x the index 0-25 for the char found at string[c].
Simplifyng: remember that 'a' is the integer ascii value 97 decimal. The subtraction of 'a' is to reduce all indexes from 'a' to 'z' to a value from 0 to 25 needed for the count[] array.
First, that code depends on the characters 'a' through 'z' being represented consecutively, something that's common but not guaranteed.
Second,
int c = 0, count[26] = {0}, x;
while (string[c] != '\0') {
/** Considering characters from 'a' to 'z' only and ignoring others. */
if (string[c] >= 'a' && string[c] <= 'z') {
x = string[c] - 'a';
count[x]++;
}
has several issues and I'd say is more clear as
#include <ctype.h>
// multiple variables on one line is ***very*** bug prone
// so don't do it
int c = 0;
int count[26] = {0};
// set the input - unsigned is important
unsigned char *string = ...;
// loop until the character pointed at by string is '\0'
while ( *string )
{
// islower() returns non-zero only if the unsigned char value
// passed is a lower-case letter.
//
// If the input int value can't be represented as an unsigned
// char the results are undefined behavior (because tolower()
// actually takes an int argument.)
//
// signed char will be sign-extended when passed as an int argument
if ( islower( *string ) )
{
// get the "index" of the lower-case letter
// a -> 0, b -> 1, z -> 25
// depends on a-z being consecutive - not necessarily true
int x = *string - 'a';
// increment the number of times this lower-case character
// is in this string
count[x]++;
}
// go to the next character in the string
string++;
}
Note that there is zero effort on my part to reduce the number of lines used. You gain nothing by cramming code into fewer lines, but you will make the code harder to read and therefore more bug prone.
A better way to count characters in a string:
#include <limits.h>
void countChars( unsigned char *string )
{
int counts[ UCHAR_MAX ] = { 0 };
while ( *string )
{
counts[ *string ]++;
string++;
}
}
If you want to count lower-case characters:
#include <limits.h>
void countLowerCaseChars( unsigned char *string )
{
int counts[ UCHAR_MAX ] = { 0 };
while ( *string )
{
counts[ tolower( *string ) ]++;
string++;
}
}

Can we set a variable to a number range in C?

What I'm thinking of is something like this:
range = range <= '9' && range >= '0';
I want to extract a contiguous sequence of digits from a string. And once the program find a non-digit after it finds the sequence of digits, I want it to break out of the loop using break; in the second if-statement (line 59). And I think it would be much easier if I can just write the condition using a variable.
What I want to say in line 59 is "If the var digit_flag is TRUE and the element in the array s is included in the var range(which is a number range), then break;"
Can it be done?
If it can't, why not?
int i = 0;
int size_of_s = 0;
int digit_flag = FALSE;
while (s[i] != '\0') {
if (s[i] == ' ') {
i++;
} else if (s[i] <= '9' && s[i] >= '0') {
size_of_s++;
i++;
digit_flag = TRUE;
}
if (digit_flag == TRUE && s[i] != range) {
break;
}
}
What I want to say in line 59 is "If the var digit_flag is TRUE and the element in the array s is included in the var range(which is a number range), then break;"
Can it be done?
As far as I know this can not be done in C.
If it can't, why not?
Because there is no relational or comparison operator in the C language which means "operand 1 is within the range of operand 2" (even if the second operand is an array). You need to use a logical AND (&&) of two conditions (>= A, <= B).
If you don't want to use a standard function - such as isdigit(), which will use the range 0-9 - you could use a macro
#define IS_IN_RANGE(x, min, max) (x >= min && x <= max)
or inline function.
static inline int is_in_range(int x, int min, int max) {
return (x >= min && x <= max);
}
If you want a "range" in C, you have to create one yourself:
// integer range class
// in this case it could also be a char range
struct int_range {
int start;
int end;
};
// range method to test for inclusinon
// in this case range could be passed as value efficiently, too,
// but passing as const pointer is more generic, so better example
bool int_range_contains(const struct int_range *range, int value) {
return value >= range->start && value <= range->end;
}
// example usage
void func(void) {
struct range digit_chars = { '0', '9' };
int character = 'a';
if (int_range_contains(&digit_chars, character)) {
// something
}
}
Of course this is a total overkill for this case. Your current if (s[i] <= '9' && s[i] >= '0') is better, and every C programmer immediately sees what's going on there.
Instead of
digit_flag == TRUE && s[i] != range
you can re-use what you already wrote
digit_flag == TRUE && !(s[i] <= '9' && s[i] >= '0')
If you want to extract the number sequence part in a string like
char str[]="hello1234isthesequence.";
you could just do
char seq[30];
if( sscanf(str, "%*[^0-9]%[0-9]", seq)==1 )
{
printf("\nThe sequence is: %s", seq);
}
where the %*[^0-9] is used to read everything from str[] till a non-digit character is encountered and the * is to suppress it ie, it will be discarded and won't be assigned to anywhere.
Next the %[0-9] will read the remaining part of the string in str till and excluding non-number and assign it to seq.
sscanf() will return the number of total successful assignments that it made, which in this case should be 1.
You may change the size of seq as per the size of the input string and change the width specifier in the format string of scanf() to avoid overflow.

Decimal to Binary in C

I'm creating a program that adds and subtracts 2 numbers. Then I have to output this answer into different bases.
My answer is in decimal format, of type long double, such as:
long double answer;
answer = numberOne + numberTwo;
I want to convert this answer into binary. Now I have code used earlier in my program that does this, but with a char pointer:
char * decimalBinary (char * decimalNumber)
{
bool zeroFront = true;
int i;
int z;
int j = 0;
int n = atoi(decimalNumber);
char * binaryNum = malloc(32+1);
binaryNum[32] = '\0';
int current_index=1;
int end_index = strlen(decimalNumber)-1;
//Error check for valid decimal input, needed error check for beginning of code
while(current_index <= end_index)
{
if(decimalNumber[current_index] != '0' &&decimalNumber[current_index] != '1' &&decimalNumber[current_index] != '2' &&decimalNumber[current_index] != '3' &&decimalNumber[current_index] != '4' &&decimalNumber[current_index] != '5' &&dec[current_index] != '6' &&dec[current_index] != '7' &&decimalNumber[current_index] != '8' &&decimalNumber[current_index] != '9')
{
binaryNum[0] = -8;
return binaryNum;
}
current_index++;
}
for (i = 31; i >= 0; i--) {
z = n >> i;
if (z & 1)
{
binaryNum[j] = '1';
j++;
zeroFront = false;
}
else if (!zeroFront)
{
binaryNum[j] = '0';
j++;
}
}
binaryNum[j] = '\0';
return binaryNum;
}
My preferred solution is to use the code I already have in my program to convert my answer into a binary format, but as you can see the parameters are conflicting, and I'm not sure how to go about doing that.
Another possible solution that detracts from having reusable code in my program, is to create a different function all together that converts a decimal to a binary, but accepting a parameter of type long double, which is a bit unclear to me as well.
Edit:
Instead of long double, my answer is of type int.
If you really want to reuse your function without modifications, you can transform answer into a decimal string and pass the string to your function.
char stringAnswer[20];
sprintf(stringAnswer, "%d", answer);
printf("the binary answer is %s\n", decimalBinary(stringAnswer));
But a better solution should be to split the function decimalBinary into two functions : the first one to check that all digits are ok, and the second one to convert a int into a binary string.
Then you'll be able to call directly this second function with answer as parameter.
Rather than use a magic number 32, better to let the compiler deduce the needed size as an int is not always 32 bits. Checking allocation results is a good habit.
#include <assert.h>
#include <stdlib.h>
#define INT_MAX_BIN_WIDTH (sizeof(int) * CHAR_BIT)
char * binaryNum = malloc(INT_MAX_BIN_WIDTH+1);
assert(binaryNum != NULL);
binaryNum[INT_MAX_BIN_WIDTH] = '\0'; // null character
Rather than checking against each digit, since '0' to '9' must be sequential:
// if(decimalNumber[current_index] != '0' &&decimalNumber[current_index] != '1' ...
if (decimalNumber[current_index] < '0' || decimalNumber[current_index] >= '9') ...
// or
if (!isdigit((unsigned char) decimalNumber[current_index])) ...
Problem does not address negative numbers. Better to state that they will not occur or better, make code handle them.
Code allocates memory, but does not free it. Consider letting the higher level code allocate/free and supply the needed buffer to decimalBinary(char *dest, size_t size, const char *src). Robust code would supply the size too.
char *binaryNum = malloc(INT_MAX_BIN_WIDTH+1);
assert(binaryNum != NULL);
decimalBinary(binaryNum, INT_MAX_BIN_WIDTH+1, "123");
do_something(binaryNum);
free(binaryNum);
Following is a solution that is not limited to 32 bits. It does not cope with negative numbers nor memory allocation - certainly it should provide some ideas for your eventual solution.
#include <stdio.h>
#include <string.h>
static void times10(char *binaryNumber, int carry) {
size_t length = strlen(binaryNumber);
size_t i = length;
while (i > 0) {
i--;
int sum = (binaryNumber[i] - '0') * 10 + carry;
binaryNumber[i] = sum % 2 + '0';
carry = sum / 2;
}
while (carry) {
memmove(&binaryNumber[1], &binaryNumber[0], ++length);
binaryNumber[0] = carry % 2 + '0';
carry /= 2;
}
}
char *decimalBinary(char *binaryNumber, const char *decimalNumber) {
strcpy(binaryNumber, "0");
int ch;
while ((ch = *decimalNumber++) >= '0' && (ch <= '9')) {
times10(binaryNumber, ch - '0');
}
return binaryNumber;
}
int main(void) {
char buf10[200];
puts(decimalBinary(buf10, "123"));
puts(decimalBinary(buf10, "123456"));
puts(decimalBinary(buf10, "123456789012345678901234567890"));
return 0;
}

Create char array from int in C

How do you put an int into a char array?
int x = 21, i = 3;
char length[4];
while(i >= 0) {
length[i] = (char) (x % 10);
x /= 10;
i--;
} printf("%s\n", length);
// length should now be "0021"
The string comes out blank instead.
Note: This is not a duplicate of "How do I convert from int to chars in C++?" because I also need padding. i.e. "0021" not "21"
You're not getting the character code of the digit, you're using the digit as if it were its own character code. It should be:
length[i] = '0' + (x % 10);
You also need to add an extra element to the length array for the terminating null character:
char length[5];
length[4] = 0;
The problem in your code is basically that 1 != '1' i.e. the character is not the integer, you need to check the ascii table to see what ascii code represents the character '1' but you don't really need to know the number, you can just use '1' note the single qoutes.
But you also didn't nul terminate your string, you need to add a '\0' at the end of the string, so
int x = 21, i = 3;
char length[5];
length[4] = '\0';
while (i >= 0)
{
length[i--] = x % 10 + '0';
x /= 10;
}
printf("%s\n", length);
should work, but is unecessary, you can just
snprintf(length, sizeof(length), "%0*d", padding, x);
/* ^ this is how many characters you want */
notice that sizeof works because length is a char array, do not confuse that with the length of a string.

Questions about a Kernighan and Ritchie Excercise 2-3

I'm trying to write a program in C that converts hexadecimal numbers to integers. I've written successfully a program that converts octals to integers. However, the problems begin once I start using the letters (a-f). My idea for the program is ads follows:
The parameter must be a string that starts with 0x or 0X.
The parameter hexadecimal number is stored in a char string s[].
The integer n is initialized to 0 and then converted as per the rules.
My code is as follows (I've only read up to p37 of K & R so don't know much about pointers) :
/*Write a function htoi(s), which converts a string of hexadecimal digits (including an optional 0x or 0X) into its equivalent integer value. The allowable digits are 0 through 9, a through f, and A through F.*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
int htoi(const char s[]) { //why do I need this to be constant??
int i;
int n = 0;
int l = strlen(s);
while (s[i] != '\0') {
if ((s[0] == '0' && s[1] == 'X') || (s[0] == '0' && s[1] == 'x')) {
for (i = 2; i < (l - 1); ++i) {
if (isdigit(s[i])) {
n += (s[i] - '0') * pow(16, l - i - 1);
} else if ((s[i] == 'a') || (s[i] == 'A')) {
n += 10 * pow(16, l - i - 1);
} else if ((s[i] == 'b') || (s[i] == 'B')) {
n += 11 * pow(16, l - i - 1);
} else if ((s[i] == 'c') || (s[i] == 'C')) {
n += 12 * pow(16, l - i - 1);
} else if ((s[i] == 'd') || (s[i] == 'D')) {
n += 13 * pow(16, l - i - 1);
} else if ((s[i] == 'e') || (s[i] == 'E')) {
n += 14 * pow(16, l - i - 1);
} else if ((s[i] == 'f') || (s[i] == 'F')) {
n += 15 * pow(16, l - i - 1);
} else {
;
}
}
}
}
return n;
}
int main(void) {
int a = htoi("0x66");
printf("%d\n", a);
int b = htoi("0x5A55");
printf("%d\n", b);
int c = htoi("0x1CA");
printf("%d\n", c);
int d = htoi("0x1ca");
printf("%d\n", d);
}
My questions are:
1. If I don't use const in the argument for htoi(s), i get the following warnings from the g++ compiler :
2-3.c: In function ‘int main()’: 2-3.c:93:20: warning: deprecated
conversion from string constant to ‘char*’ [-Wwrite-strings]
2-3.c:97:22: warning: deprecated conversion from string constant to
‘char*’ [-Wwrite-strings] 2-3.c:101:21: warning: deprecated conversion
from string constant to ‘char*’ [-Wwrite-strings] 2-3.c:105:21:
warning: deprecated conversion from string constant to ‘char*’
[-Wwrite-strings]
Why is this?
2.Why is my program taking so much time to run? I haven't seen the results yet.
3.Why is it that when I type in cc 2-3.c instead of g++ 2-3.c in the terminal, I get the following error message:
"undefined reference to `pow'"
on every line that I've used the power function?
4. Please do point out other errors/ potential improvements in my program.
If I don't use const in the argument for htoi(s), i get the following warnings from the g++ compiler
The const parameter should be there, because it is regarded as good and proper programming to never typecast away const from a pointer. String literals "..." should be treated as constants, so if you don't have const as parameter, the compiler thinks you are casting away the const qualifier.
Furthermore, you should declare all pointer parameters that you don't intend to modify the contents of as const, Google the term const correctness.
Why is my program taking so much time to run? I haven't seen the results yet.
I think mainly because you have made an initialization goof-up. int i; i contains rubbish. Then while (s[rubbish_value] != '\0'). This function can be written a whole lot better too. Start by checking for the 0x in the start of the string, if they aren't there, signal some error (return NULL?), otherwise discard them. Then start one single loop after that, you don't need 2 loops.
Note that the pow() function deals with float numbers, which will make your program a slight bit slower. You could consider using an integer-only version. Unfortunately there is no such function in standard C, so you will have to found one elsewhere.
Also consider the function isxdigit(), a standard function in ctype.h, which checks for digits 0-9 as well as hex letters A-F or a-f. It may however not help with performance, as you will need to perform different calculations for digits and letters.
For what it is worth, here is a snippet showing how you can convert a single char to a hexadecimal int. It is not the most optimized version possible, but it takes advantage of available standard functions, for increased readability and portability:
#include <ctype.h>
uint8_t hexchar_to_int (char ch)
{
uint8_t result;
if(isdigit(ch))
{
result = ch - '0';
}
else if (isxdigit(ch))
{
result = toupper(ch) - 'A' + 0xA;
}
else
{
// error
}
return result;
}
Don't use a C++ compiler to compile a C program. That's my first advice to you.
Secondly const in a function parameter for a char * ensures that the programmer doesn't accidentally modify the string.
Thirdly you need to include the math library with -lm as stated above.
a const char[] means that you cannot change it in the function. Casting from a const to not-const gives a warning. There is much to be said about const. Check out its Wikipedia page.
--
Probably, cc doesn't link the right libraries. Try the following build command: cc 2-3.c -lm
Improvements:
Don't use pow(), it is quite expensive in terms of processing time.
Use the same trick with the letters as you do with the numbers to get the value, instead of using fixed 'magic' numbers.
You don't need the last else part. Just leave it empty (or put an error message there, because those characters aren't allowed).
Good luck!
About my remark about the pow() call (with the use of the hexchar_to_int() function described above, this is how I'd implement this (without error checking):
const char *t = "0x12ab";
int i = 0, n = 0;
int result = 0;
for (i = 2; i < strlen(t); i++) {
n = hexchar_to_int(t[i]);
result |= n;
result <<= 4;
}
/* undo the last shift */
result >>= 4;
I just worked through this exercise myself, and I think one of the main ideas was to use the knowledge that chars can be compared as integers (they talk about this in chapter 2).
Here's my function for reference. Thought it may be useful as the book doesn't contain answers to exercises.
int htoi(char s[]) {
int i = 0;
if(s[i] == '0') {
++i;
if(s[i] == 'x' || s[i] == 'X') {
++i;
}
}
int val = 0;
while (s[i] != '\0') {
val = 16 * val;
if (s[i] >= '0' && s[i] <= '9')
val += (s[i] - '0');
else if (s[i] >= 'A' && s[i] <= 'F')
val += (s[i] - 'A') + 10;
else if (s[i] >= 'a' && s[i] <= 'f')
val += (s[i] - 'a') + 10;
else {
printf("Error: number supplied not valid hexadecimal.\n");
return -1;
}
++i;
}
return val;
}
Always init your variables int i=0, otherwise i will contain a garbage value, could be any number, not necessary 0 as you expect. You're running the while statement in an infinite loop, that's why it takes forever to get the results, print i to see why. Also, add a break if the string doesn't start with 0x, will avoid the same loop issue when the user is used on a random string. As others mention you need to import the library containing pow function and declare your string with const to get rid of the warning.
This is my version of program for the question above. It converts the string of hex into decimal digits irrespective of optional prefix(0x or 0X).
4 important library functions used are strlen(s), isdigit(c), isupper(c), isxdigit(c), pow(m,n)
Suggestions to improve the code are welcome :)
/*Program - 5d Function that converts hex(s)into dec -*/
#include<stdio.h>
#include<stdlib.h>
#include<math.h> //Declares mathematical functions and macros
#include<string.h> //Refer appendix in Page 249 (very useful)
#define HEX_LIMIT 10
int hex_to_dec(char hex[]) //Function created by me :)
{
int dec = 0; //Initialization of decimal value
int size = strlen(hex); //To find the size of hex array
int temp = size-1 ; //Pointer pointing the right element in array
int loop_limit = 0; //To exclude '0x' or 'OX' prefix in input
if(hex[0]=='0' && ((hex[1]=='x') || (hex[1]=='X')))
loop_limit = 2;
while(temp>=loop_limit)
{
int hex_value = 0; //Temporary value to hold the equivalent hex digit in decimal
if(isdigit(hex[temp]))
hex_value = (hex[(temp)]-'0') ;
else if(isxdigit(hex[temp]))
hex_value = (toupper(hex[temp])-'A' + 10);
else{
printf("Error: No supplied is not a valid hex\n\n");
return -1;
}
dec += hex_value * pow(16,(size-temp-1)); //Computes equivalent dec from hex
temp--; //Moves the pointer to the left of the array
}
return dec;
}
int main()
{
char hex[HEX_LIMIT];
printf("Enter the hex no you want to convert: ");
scanf("%s",hex);
printf("Converted no in decimal: %d\n", hex_to_dec(hex));
return 0;
}

Resources