Page 1 of 2

char* to int, has to be an easier way

Posted: Sat Mar 01, 2014 2:33 am
by BASICFreak
Ok, what I have works but it is the worst looking function I have:

Code: Select all

int						charTOint(char* in)
{
	int			out = 0;
	int i;
	int z = 0;
	for (i=strlen(in)-2 ; i>=0;i--,z++)
	{
		switch (in[i])
		{
			case '1':
				out += 1*exponent(10, z);
				break;
			case '2':
				out += 2*exponent(10, z);
				break;
			case '3':
				out += 3*exponent(10, z);
				break;
			case '4':
				out += 4*exponent(10, z);
				break;
			case '5':
				out += 5*exponent(10, z);
				break;
			case '6':
				out += 6*exponent(10, z);
				break;
			case '7':
				out += 7*exponent(10, z);
				break;
			case '8':
				out += 8*exponent(10, z);
				break;
			case '9':
				out += 9*exponent(10, z);
				break;
		}
	}
	return		out;
}
Is there an easier way of going about this?

Hopefully it is obviously easier than I think and I'm just tired, it is late...

Re: char* to int, has to be an easier way

Posted: Sat Mar 01, 2014 3:00 am
by bwat
You're processing the string in the wrong direction.

Hint 1: 123*10+4 is 1234, and 1234*10+5 is 12345
Hint 2: '3'-'0' is 3

Re: char* to int, has to be an easier way

Posted: Sat Mar 01, 2014 3:43 am
by iansjack
Is there an easier way of going about this?
I find it difficult to think of a more convoluted way. The entire switch statement can be replaced with a single expression and you can eliminate the variables "i" and "z". I'm not going to insult your intelligence by spoonfeeding you with a solution.

Re: char* to int, has to be an easier way

Posted: Sat Mar 01, 2014 4:17 am
by bwat
iansjack wrote:
Is there an easier way of going about this?
I find it difficult to think of a more convoluted way. The entire switch statement can be replaced with a single expression and you can eliminate the variables "i" and "z". I'm not going to insult your intelligence by spoonfeeding you with a solution.
What he's done is completely in line with how positional number systems are taught. The only thing he was missing was the application of Horner's rule:

Code: Select all

 str[n]*x^n+str[n-1]*x^(n-1)+...+str[0]=((str[n]*x+str[n-1])*x+...)*x+str[0]. 
His code isn't convoluted, in fact it's quite understandable but inefficient on a binary machine (exponent(10,X) would be more efficient on a decimal machine). The use of Horner's rule and knowledge about the lexicographical ordering of the ASCII alphabet makes the experienced programmer's solution difficult to understand but efficient to execute.

Re: char* to int, has to be an easier way

Posted: Sat Mar 01, 2014 12:21 pm
by BASICFreak
Thanks for all the replies, here is what I have now and I will continue to modify it as time goes on but it's much simpler now.

Code: Select all

int						charTOint(char* in)
{
	int			out = 0;
	int i;
	int z = 0;
	for (i=strlen(in)-2 ; i>=0;i--,z++) out += (in[i] - '0') * exponent(10, z);
	return		out;
}
Must have been late I posted and don't even remember getting to bed ;)
And how can I forget ASCII '7' - ASCII '0' = # 7

For now I'll leave int z & i and exponent() - I have more important segments to worry about.

Re: char* to int, has to be an easier way

Posted: Sat Mar 01, 2014 1:06 pm
by sortie
You really are trying to be more clever than you need to be, it can be done extremely elegantly:

Code: Select all

unsigned int unsigned_int_of_string(const char* string)
{
	unsigned int result = 0;
	for ( size_t i = 0; string[i]; i++ )
		result = result * 10 + string[i] - '0';
	return result;
}
(without support for negative integers or error handling - that's trivial to add if desired)

There really isn't any need to mess with exponents (is that floats?) or taking the string length, when you can inductively solve the problem by reducing it to adding one more digit to a partial solution.

Re: char* to int, has to be an easier way

Posted: Sat Mar 01, 2014 1:15 pm
by iansjack
Better but I would replace the "for" loop with a "while" and do away with the unnecessary variable "i".

Re: char* to int, has to be an easier way

Posted: Sat Mar 01, 2014 1:52 pm
by sortie
iansjack wrote:Better but I would replace the "for" loop with a "while" and do away with the unnecessary variable "i".
Now you are just needlessly micro-optimizing and bike-shedding. When I make your change my local gcc outputs exactly the same assembly (instructions in slightly different order) when compiling -Os (optimize for size). It doesn't really matter as the code is equivalent, the only difference is readability and the ease with which it can be statically verified as correct. To that end, I consider it superior using strings as arrays rather than pointers that are rewritten and dereferenced. Besides, if you wanted it pure, you'd do it recursively functional style.

Re: char* to int, has to be an easier way

Posted: Sat Mar 01, 2014 1:58 pm
by BASICFreak
sortie wrote:You really are trying to be more clever than you need to be, it can be done extremely elegantly:

Code: Select all

unsigned int unsigned_int_of_string(const char* string)
{
	unsigned int result = 0;
	for ( size_t i = 0; string[i]; i++ )
		result = result * 10 + string[i] - '0';
	return result;
}
(without support for negative integers or error handling - that's trivial to add if desired)

There really isn't any need to mess with exponents (is that floats?) or taking the string length, when you can inductively solve the problem by reducing it to adding one more digit to a partial solution.
FYI 'size_t i' should be declared before the for loop, only in C99 mode can it be declared inside the loop.

so here is the code I remade:

Code: Select all

unsigned int			charTOint(char* in)
{
	unsigned int ret = 0;
	while (*in != 0)
	{
		if (*in < '0' || *in > '9') return -1;
		ret = ret * 10 + *in - '0';
		*in++;
	}
	return ret;
}
Tested and works fine, and returns -1 on error

I could not think of how to process in order thanks for that, makes more sense than what I was doing.

Re: char* to int, has to be an easier way

Posted: Sat Mar 01, 2014 2:21 pm
by Combuster
BASICFreak wrote:FYI 'size_t i' should be declared before the for loop, only in C99 mode can it be declared inside the loop.
And you're deliberately lagging behind 25 years :wink:

Re: char* to int, has to be an easier way

Posted: Sat Mar 01, 2014 2:28 pm
by bwat
BASICFreak wrote:

Code: Select all

unsigned int			charTOint(char* in)
{
	unsigned int ret = 0;
	while (*in != 0)
	{
		if (*in < '0' || *in > '9') return -1;
		ret = ret * 10 + *in - '0';
		*in++;
	}
	return ret;
}
Tested and works fine, and returns -1 on error

I could not think of how to process in order thanks for that, makes more sense than what I was doing.
You've written a function with return type unsigned int that returns -1 on error. Interesting....... :)

Re: char* to int, has to be an easier way

Posted: Sat Mar 01, 2014 2:33 pm
by sortie
BASICFreak wrote:FYI 'size_t i' should be declared before the for loop, only in C99 mode can it be declared inside the loop.
Please simply cease to use C89 and upgrade to C11, or at least C99. It's entirely silly to use obsolete versions of the C standard that has been replaced. I realized the C89 portability issue when I wrote the code and I deliberately did it anyway. :-)
BASICFreak wrote:*in++;
Why are you referencing the pointer prior to advancing it, rather than just advancing it? :-)

Re: char* to int, has to be an easier way

Posted: Sat Mar 01, 2014 2:44 pm
by iansjack
sortie wrote:
iansjack wrote:Better but I would replace the "for" loop with a "while" and do away with the unnecessary variable "i".
Now you are just needlessly micro-optimizing and bike-shedding. When I make your change my local gcc outputs exactly the same assembly (instructions in slightly different order) when compiling -Os (optimize for size). It doesn't really matter as the code is equivalent, the only difference is readability and the ease with which it can be statically verified as correct. To that end, I consider it superior using strings as arrays rather than pointers that are rewritten and dereferenced. Besides, if you wanted it pure, you'd do it recursively functional style.
No. I'm lazy and cutting down on the typing. Why use two words when one does the job? ;)

Re: char* to int, has to be an easier way

Posted: Sat Mar 01, 2014 2:48 pm
by BASICFreak
bwat wrote:
BASICFreak wrote:

Code: Select all

unsigned int			charTOint(char* in)
{
	unsigned int ret = 0;
	while (*in != 0)
	{
		if (*in < '0' || *in > '9') return -1;
		ret = ret * 10 + *in - '0';
		*in++;
	}
	return ret;
}
Tested and works fine, and returns -1 on error

I could not think of how to process in order thanks for that, makes more sense than what I was doing.
You've written a function with return type unsigned int that returns -1 on error. Interesting....... :)
Yea, I realized that after posting and switched to 0 on error (only issue is if 0 is the right output I'm screwed...)

bochs out (snip-it):
Testing char to int of '2048': 2048, '44578': 44578, '64728': 64728, '4d58': 0
sortie wrote:Why are you referencing the pointer prior to advancing it, rather than just advancing it? :-)
Because that is the way I know...

C is not my native language, learning so much within 1500 lines. I'm starting to miss the OO languages though - or at the very least standard libraries.

And I'll continue to make my code C89 standard so I don't have to worry about anyone (mostly me) missing a -C99 gcc tag.

Re: char* to int, has to be an easier way

Posted: Sat Mar 01, 2014 3:02 pm
by Antti
iansjack wrote:Why use two words when one does the job?
Readability is extremely important. Pointer arithmetic adds one low-level detail that can be avoided. The example sortie gave us is more elegant because it is more "portable" to more restricted languages (read: safe languages).