Convert char array to a int number in C - c

I want to convert a char array[] like:
char myarray[4] = {'-','1','2','3'}; //where the - means it is negative
So it should be the integer: -1234
using standard libaries in C. I could not find any elegant way to do that.
I can append the '\0' for sure.

I personally don't like atoi function. I would suggest sscanf:
char myarray[5] = {'-', '1', '2', '3', '\0'};
int i;
sscanf(myarray, "%d", &i);
It's very standard, it's in the stdio.h library :)
And in my opinion, it allows you much more freedom than atoi, arbitrary formatting of your number-string, and probably also allows for non-number characters at the end.
EDIT
I just found this wonderful question here on the site that explains and compares 3 different ways to do it - atoi, sscanf and strtol. Also, there is a nice more-detailed insight into sscanf (actually, the whole family of *scanf functions).
EDIT2
Looks like it's not just me personally disliking the atoi function. Here's a link to an answer explaining that the atoi function is deprecated and should not be used in newer code.

Why not just use atoi? For example:
char myarray[4] = {'-','1','2','3'};
int i = atoi(myarray);
printf("%d\n", i);
Gives me, as expected:
-123
Update: why not - the character array is not null terminated. Doh!

It isn't that hard to deal with the character array itself without converting the array to a string. Especially in the case where the length of the character array is know or can be easily found. With the character array, the length must be determined in the same scope as the array definition, e.g.:
size_t len sizeof myarray/sizeof *myarray;
For strings you, of course, have strlen available.
With the length known, regardless of whether it is a character array or a string, you can convert the character values to a number with a short function similar to the following:
/* convert character array to integer */
int char2int (char *array, size_t n)
{
int number = 0;
int mult = 1;
n = (int)n < 0 ? -n : n; /* quick absolute value check */
/* for each character in array */
while (n--)
{
/* if not digit or '-', check if number > 0, break or continue */
if ((array[n] < '0' || array[n] > '9') && array[n] != '-') {
if (number)
break;
else
continue;
}
if (array[n] == '-') { /* if '-' if number, negate, break */
if (number) {
number = -number;
break;
}
}
else { /* convert digit to numeric value */
number += (array[n] - '0') * mult;
mult *= 10;
}
}
return number;
}
Above is simply the standard char to int conversion approach with a few additional conditionals included. To handle stray characters, in addition to the digits and '-', the only trick is making smart choices about when to start collecting digits and when to stop.
If you start collecting digits for conversion when you encounter the first digit, then the conversion ends when you encounter the first '-' or non-digit. This makes the conversion much more convenient when interested in indexes such as (e.g. file_0127.txt).
A short example of its use:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int char2int (char *array, size_t n);
int main (void) {
char myarray[4] = {'-','1','2','3'};
char *string = "some-goofy-string-with-123-inside";
char *fname = "file-0123.txt";
size_t mlen = sizeof myarray/sizeof *myarray;
size_t slen = strlen (string);
size_t flen = strlen (fname);
printf ("\n myarray[4] = {'-','1','2','3'};\n\n");
printf (" char2int (myarray, mlen): %d\n\n", char2int (myarray, mlen));
printf (" string = \"some-goofy-string-with-123-inside\";\n\n");
printf (" char2int (string, slen) : %d\n\n", char2int (string, slen));
printf (" fname = \"file-0123.txt\";\n\n");
printf (" char2int (fname, flen) : %d\n\n", char2int (fname, flen));
return 0;
}
Note: when faced with '-' delimited file indexes (or the like), it is up to you to negate the result. (e.g. file-0123.txt compared to file_0123.txt where the first would return -123 while the second 123).
Example Output
$ ./bin/atoic_array
myarray[4] = {'-','1','2','3'};
char2int (myarray, mlen): -123
string = "some-goofy-string-with-123-inside";
char2int (string, slen) : -123
fname = "file-0123.txt";
char2int (fname, flen) : -123
Note: there are always corner cases, etc. that can cause problems. This isn't intended to be 100% bulletproof in all character sets, etc., but instead work an overwhelming majority of the time and provide additional conversion flexibility without the initial parsing or conversion to string required by atoi or strtol, etc.

So, the idea is to convert character numbers (in single quotes, e.g. '8') to integer expression. For instance char c = '8'; int i = c - '0' //would yield integer 8; And sum up all the converted numbers by the principle that 908=9*100+0*10+8, which is done in a loop.
char t[5] = {'-', '9', '0', '8', '\0'}; //Should be terminated properly.
int s = 1;
int i = -1;
int res = 0;
if (c[0] == '-') {
s = -1;
i = 0;
}
while (c[++i] != '\0') { //iterate until the array end
res = res*10 + (c[i] - '0'); //generating the integer according to read parsed numbers.
}
res = res*s; //answer: -908

It's not what the question asks but I used #Rich Drummond 's answer for a char array read in from stdin which is null terminated.
char *buff;
size_t buff_size = 100;
int choice;
do{
buff = (char *)malloc(buff_size *sizeof(char));
getline(&buff, &buff_size, stdin);
choice = atoi(buff);
free(buff);
}while((choice<1)&&(choice>9));

Related

How can I extract an integer from within a string?

I'm working on an assignment and as part of it I need to extract the integer from a string.
I've tried using the atoi() function, but it always returns a 0, so then I switched up to strtol(), but it still returns a 0.
The goal is to extract the integers from the string and pass them as arguments to a different function. I'm using a function that then uses these values to update some data (update_stats).
Please keep in mind that I'm fairly new to programming in the C language, but this was my attempt:
void get_number (char str[]) {
char *end;
int num;
num = strtol(str, &end, 10);
update_stats(num);
num = strtol(end, &end, 10);
update_stats(num);
}
The purpose of this is in a string "e5 d8" (for example) I would extract the 5 and the 8 from that string.
The format of the string is always the same.
How can I do this?
strtol doesn't find a number in a string. It converts the number at the beginning of the string. (It does skip whitespace, but nothing else.)
If you need to find where a number starts, you can use something like:
const char* nump = strpbrk(str, "0123456789");
if (nump == NULL) /* No number, handle error*/
(man strpbrk)
If your numbers might be signed, you'll need something a bit more sophisticated. One way is to do the above and then back up one character if the previous character is -. But watch out for the beginning of the string:
if ( nump != str && nump[-1] == '-') --nump;
Just putting - into the strpbrk argument would produce false matches on input like non-numeric7.
If the format is always like this, then this could also work
#include <stdio.h>
int main()
{
char *str[] = {"a5 d8", "fe55 eec2", "a5 abc111"};
int num1, num2;
for (int i = 0; i < 3; i++) {
sscanf(str[i], "%*[^0-9]%d%*[^0-9]%d", &num1, &num2);
printf("num1: %d, num2: %d\n", num1, num2);
}
return 0;
}
Output
num1: 5, num2: 8
num1: 55, num2: 2
num1: 5, num2: 111
%[^0-9] will match any non digit character. By adding the * like this %*[^0-9] indicates that the data is to be read from the string, but ignored.
I suggest you write the logic on your own. I know, it's like reinventing the wheel, but in that case, you will have an insight into how the library functions actually work.
Here is a function I propose:
bool getNumber(str,num_ptr)
char* str;
long* num_ptr;
{
bool flag = false;
int i = 0;
*num_ptr = 0;
char ch = ' ';
while (ch != '\0') {
ch = *(str + i);
if (ch >= '0' && ch <= '9') {
*num_ptr = (*num_ptr) * 10 + (long)(ch - 48);
flag = true;
}
i++;
}
return flag;
}
Don't forget to pass a string with a \0 at the end :)

how to fix this code so that it can test the integers present next to the character?

Given a string containing alphanumeric characters, calculate the sum of all numbers present in the string.
The problem with my code is that it displays the integers present before the characters, but it is not summing up the integers after the characters.
The execution is easy in python and C++ but I cant get it done using C! Can anyone please verify where I have done wrong? << thank you !
enter code here
#include<stdio.h>
#include<string.h>
int convert(char[]);
int main()
{
char ch[100],temp[100]={0};
int i=0,s=0,j=0,n;
scanf("%s",ch);
for(i=0;i<strlen(ch);i++)
{
if((ch[i]>='0') && (ch[i]<='9'))
{
temp[j]=ch[i];
j++;
}
else
{
if(temp[0]== '\0')
{
continue;
}
else
{
n=convert(temp);
s+=n;
temp[0]= '\0';
j=0;
}
}
}
printf("%d",s);
return 0;
}
int convert(char s[]) //converting string to integer
{
int n=0;
for(int i=0;i<strlen(s);i++)
{
n= n * 10 + s[i] - '0';
}
return n;
}
Input : 12abcd4
Expected output : 16
But the output is 12 for my code.
There are two problems in your code. The first was mentioned in the comments : if the last character is a digit, the last "number section" will not be taken into account. But I don't think that the solution given in the comments is good because if the last character is not a digit, you will have a wrong value. To correct this, I added an if statement that check if the last character is a digit, if so call convert().
The second problem is that strlen return the number of characters in you string from the beginning until it finds an '\0'. The way you used your string lead to the follow problem :
ch = "12abcd4".
At first you have temp = '1' + '2' + '\0'...
After calling convert() you set temp[0] to '\0', thus temp = '\0' + '2' + '\0'... .
And when you start reading digit again, you set '4' in temp[0]. Your string is now : '4' + '2' + '\0'... .
The n returned will be 42 and your result 54 (12+42). There are several solution to have the expected behavior, I chose to use your variable j to indicate how many characters should be read instead of using strlen() :
#include<stdio.h>
#include<string.h>
int convert(char[], int size);
int main() {
char ch[100],temp[100]={0};
int i=0,s=0,j=0,n;
scanf("%s",ch);
for(i=0;i<strlen(ch);i++) {
if((ch[i]>='0') && (ch[i]<='9')) {
temp[j]=ch[i];
j++;
// change here
if(i == strlen(ch) - 1) {
n=convert(temp, j);
s+=n;
}
}
else {
// change here
n=convert(temp, j);
s+=n;
if(temp[0]== '\0') {
continue;
}
temp[0]= '\0';
j=0;
}
}
printf("%d\n",s);
return 0;
}
//change here
int convert(char s[], int size) {
int n=0;
for(int i=0;i<size;i++) {
n= n * 10 + s[i] - '0';
}
return n;
}
You could use a combination of strtoul() and strpbrk() to do this.
Declare two character pointers start_ptr and end_ptr and make start_ptr point to the beginning of the string under consideration.
char *start_ptr=s, *end_ptr;
where s is the character array of size 100 holding the string.
Since your string has only alphanumeric characters, there is no - sign and hence there are no negative numbers. So we can get away with using unsigned integers.
We are using strtoul() from stdlib.h to perform the string to integer conversion. So let's declare two variables: rv for holding the value returned by strtoul() and sum to hold the sum of numbers.
unsigned long rv, sum_val=0;
Now use a loop:
for(; start_ptr!=NULL; )
{
rv = strtoul(start_ptr, &end_ptr, 10);
if(rv==ULONG_MAX && errno==ERANGE)
{
//out of range!
printf("\nOut of range.");
break;
}
else
{
printf("\n%lu", rv);
sum_val += rv;
start_ptr=strpbrk(end_ptr, "0123456789");
}
}
strtoul() will convert as much part of the string as possible and then make end_ptr point to the first character of the part of the string that could not be converted.
It will return ULONG_MAX if the number is too big and errno would be set to ERANGE.
Otherwise the converted number is returned.
strpbrk() would search for a set of characters (in this case the characters 0-9) and return a pointer to the first match. Otherwise NULL is returned.
Don't forget to include the following header files:
stdlib.h ---> strtoul
string.h ---> strpbrk
limits.h ---> ULONG_MAX
errno.h ---> errno
In short, we could make the program to something like
for(; start_ptr!=NULL; sum_val += rv, start_ptr=strpbrk(end_ptr, "0123456789"))
{
rv = strtoul(start_ptr, &end_ptr, 10);
if(rv==ULONG_MAX && errno==ERANGE)
{
//out of range!
break;
}
}
printf("\n\n%lu", sum_val);
So the value of sum_val for the string "12abcd4" would be 16.
scanf() is usually not the best way to accept input that is not well-formatted. Maybe you can use fgets()-sscanf() combo instead.
If you must use scanf(), make sure that you check the value returned by it, which in your case must be 1 (the number of successful assignments that scanf() made).
And to prevent overflow, use a width specifier as in
scanf("%99s",ch);
instead of
scanf("%s",ch);
as 100 is the size of the ch character array and we need one extra byte to store the string delimiter (the \0 character).

What should char function return in C?

I'd like to know what should char function return?
Take this code for example:
#include <stdio.h>
char *convert(char *str);
int main() {
char *str[1000];
printf("Enter a string: ");
scanf("%[^\n]s", str);
printf("\nOutput: %s\n", str);
convert(str);
printf("\nAfter converting to lowercase: %s\n\n", str);
return 0;
}
char *convert(char *str) {
int i = 0;
char *p;
char *c;
while (str[i] != '\0') {
if (str[i] >= 'A' && str[i] <= 'Z') {
str[i] = str[i] + 32;
}
i++;
}
for (p = c = str; *p != '\0'; p++) {
*c = *p;
if (*c < '0' || *c > '9') {
c++;
}
}
*c = '\0';
return str;
}
I'm returning str in char *convert function but this code works fine even if I don't return anything or return 0. Should I change this function to void? Is this code alright?
Should I change this function to void? Is this code alright?
You always want to match the return type of the function to how your function is intended to be used. There is nothing wrong returning char * from convert. Since you do not alter the address of str within convert, that provides the option of using the return as a parameter to another function, such as:
printf("\nAfter converting to lowercase: %s\n\n", convert (str));
If you had declared convert as void, that would no longer be an option. However, by returning str, you also lose the ability to change where str points within the function. (so for example in converting to lowercase, you couldn't simply increment str++ in your function) Not a limitation, just something to be aware of. Really, either way is fine.
As for your convert function itself, it does not compress the spaces on either side of the digits it removes in str. For example, if you enter the string:
My dog HAS 23 Fleas
as input, you receive:
my dog has fleas
as output with the double-space (on from either side of 23 still present in the string. You can clean that up by adding a flag tracking consecutive spaces or by adding additional tests.
The final comment I would have would be to refactor your convert into two functions, one to convert to lowercase (say str2lower) and one to remove digits (say strrmdigits). The allows you to reuse the functions independently. There are many times you will want to convert to lowercase, and maybe a few you want to remove digits, but there will be very few times you want to both convert to lowercase and remove the digits from a string. So think ahead when factoring your code.
A splitting of your convert into a str2lower and strrmdigits could go something like follows:
char *str2lower (char *str) /* convert string to lower case */
{
for (char *p = str; *p; p++)
if ('A' <= *p && *p <= 'Z')
*p ^= ('A' ^ 'a'); /* works for ASCII & EBCDIC */
return str;
}
The function to remove digits while compressing surrounding whitespace into one, could look like:
char *strrmdigits (char *str) /* remove included digits */
{
char *p = str; /* pointer used to elminate digits */
int nspace = 0; /* flag tracking consequtive spaces */
for (int i = 0; str[i]; i++) /* loop over each char */
if (str[i] < '0' || '9' < str[i]) { /* digit? */
if (str[i] != ' ') { /* if not a space */
*p++ = str[i]; /* write character */
nspace = 0; /* set space count 0 */
} /* otherwise */
else if (!nspace) { /* no space written yet? */
*p++ = str[i]; /* write space */
nspace = 1; /* set space written flag */
}
}
*p = 0; /* nul-terminate at p */
return str;
}
You could then tidy up your test program a bit by removing the magic number 1000 and using a proper #define to define the needed constant. (don't use magic numbers in your code). While fgets is a better choice for user input (you simply trim the trailing '\n'), if you are going to use scanf, then you must always validate the return, and when reading strings into an array, always protect your array bounds by including a proper field width modifier to specify the maximum number of characters to read. (there is no way around it, you cannot use a variable, so the field width is a value you have to hardcode.)
With those tweaks included, you could do something like the following (making use of the return from each of the functions), e.g.
#include <stdio.h>
#define MAXC 1000 /* if you need a constant, #define one (or more) */
char *str2lower (char *str);
char *strrmdigits (char *str);
int main (void) {
char str[MAXC] = ""; /* initialize all strings zero */
printf ("Enter a string: ");
if (scanf ("%999[^\n]s", str) != 1) { /* always validate return */
fputs ("error: invalid input.\n", stderr);
return 1;
}
printf ("\nOutput: '%s'\n\n", str);
printf ("to lowercase : '%s'\n\n", str2lower (str));
printf ("digits removed: '%s'\n", strrmdigits (str));
return 0;
}
Example Use/Output
$ ./bin/charrtn
Enter a string: My dog HAS 23 Fleas
Output: 'My dog HAS 23 Fleas'
to lowercase : 'my dog has 23 fleas'
digits removed: 'my dog has fleas'
Look things over and let me know if you have further questions.

Trying to remove all numbers from a string in C

I'm trying to take all of the numbers out of a string (char*)...
Here's what I have right now:
// Take numbers out of username if they exist - don't care about these
char * newStr;
strtoul(user, &newStr, 10);
user = newStr;
My understanding is that strtoul is supposed to convert a string to an unsigned long. The characters that are not numbers are put into the passed in pointer (the 2nd arg). When i reassign user to newStr and print it, the string remains unchanged. Why is this? Does anyone know of a better method?
From the documentation example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char str[30] = "2030300 This is test";
char *ptr;
long ret;
ret = strtoul(str, &ptr, 10);
printf("The number(unsigned long integer) is %lu\n", ret);
printf("String part is |%s|", ptr);
return(0);
}
Let us compile and run the above program, this will produce the following result:
The number(unsigned long integer) is 2030300
String part is | This is test|
char* RemoveDigits(char* input)
{
char* dest = input;
char* src = input;
while(*src)
{
if (isdigit(*src)) { src++; continue; }
*dest++ = *src++;
}
*dest = '\0';
return input;
}
Test:
int main(void)
{
char inText[] = "123 Mickey 456";
printf("The result is %s\n", RemoveDigits(inText));
// Expected Output: " Mickey "
}
The numbers were removed.
Here is a C program to remove digits from a string without using inbuilt functions. The string is shifted left to overwrite the digits:
#include <stdio.h>
int main(void) {
char a[] = "stack123overflow";
int i, j;
for (i = 0; a[i] != '\0'; i ++) {
if (a[i] == '0' || a[i] == '1' || a[i] == '2' || a[i] == '3' || a[i] == '4' || a[i] == '5' || a[i] == '6' || a[i] == '7' || a[i] == '8' || a[i] == '9') {
for (j = i; a[j] != '\0'; j ++)
a[j] = a[j + 1];
i--;
}
}
printf("%s", a);
return 0;
}
Example of execution:
$ gcc shift_str.c -o shift_str
$ ./shift_str
stackoverflow
strtoul() does not extract all numbers from string, it just trying to covert string to number and convertion stops when non digit is find. So if your string starts from number strtoul() works as you expect, but if string starts from letters, strtoul() stops at the first symbol. To solve your task in simple way you should copy all non-digits to other string, that will be a result.
The problem you are having is that strtoul is converting characters at the beginning of the string into an unsigned long. Once it encounters non-numeric digits, it stops.
The second parameter is a pointer into the original character buffer, pointing at the first non-numeric character.
http://www.cplusplus.com/reference/cstdlib/strtoul/
Parameter 2 : Reference to an object of type char*, whose value is set by the function to the next character in str after the numerical value.
So, if you tried to run the function on "123abc567efg" the returned value would be 123. The original string buffer would still be "123abc567efg" with the second parameter now pointing at the character 'a' in that buffer. That is, the pointer (ptr) will have a value 3 greater than original buffer pointer (str). Printing the string ptr, would give you "abc567efg" as it simply points back into the original buffer.
To actually remove ALL the digits from the string in C you would need to do something similar to this answer : Removing spaces and special characters from string
You build your allowable function to return false on 0-9 and true otherwise. Loop through and copy out digits to a new buffer.

Convert char array to int array?

I'm beginner in C.
I have an char array in this format for example "12 23 45 9".
How to convert it in int array {12,23,45,9}?
Thanks in advance.
Use sscanf, or strtol in a loop.
The traditional but deprecated way to do this would be to use strtok(). The modern replacement is strsep(). Here's an example straight off the man page for strsep():
char **ap, *argv[10], *inputstring;
for (ap = argv; (*ap = strsep(&inputstring, " \t")) != NULL;)
if (**ap != '\0')
if (++ap >= &argv[10])
break;
That breaks inputstring up into pieces using the provided delimiters (space, tab) and iterates over the pieces. You should be able to modify the above to convert each piece into an int using atoi(). The main problem with strsep() is that it modifies the input string and is therefore not thread safe.
If you know that the input string will always contain the same number of ints, another approach would be to use sscanf() to read all the ints in one go:
char *input = "12 23 45 9";
int output[5];
sscanf(inputstring, "%d %d %d %d %d", &output[0], &output[1], &output[2], &output[3], &output[4]);
You can calculate the individual digits by using the following technique (but it won't convert them into the whole number):
Note I am using an int iteration loop to make it readable. Normally you'd just increment the char pointer itself:
void PrintInts(const char Arr[])
{
int Iter = 0;
while(Arr[Iter])
{
if( (Arr[Iter] >= '0') && (Arr[Iter]) <= '9')
{
printf("Arr[%d] is: %d",Iter, (Arr[Iter]-'0') );
}
}
return;
}
The above will convert the ASCII number back into an int number by deducting the lowest ASCII representation of the 0-9 set. So if, for example, '0' was represented by 40 (it's not), and '1' was represented by 41 (it's not), 41-40 = 1.
To get the results you want, you want to use strtok and atoi:
//Assumes Numbers has enough space allocated for this
int PrintInts(const int Numbers[] const char Arr[])
{
char *C_Ptr = strtok(Arr," ");
int Iter = 0;
while(C_Ptr != NULL)
{
Numbers[Iter] = atoi(C_Ptr);
Iter++;
C_Ptr = strtok(NULL," ");
}
return (Iter-1); //Returns how many numbers were input
}
You will need stdlib.h
//get n,maxDigits
char** p = malloc(sizeof(char*) * n);
int i;
for(i=0;i<n;i++)
p[i] = malloc(sizeof(char) * maxDigits);
//copy your {12,23,45,9} into the string array p, or do your own manipulation to compute string array p.
int* a = malloc(sizeof(int) * n);
int i;
for(i=0;i<n;i++)
a[i] = atoi(p[i]);
What about:
const char *string = "12 23 45 9";
int i, numbers[MAX_NUMBERS]; //or allocated dynamically
char *end, *str = string;
for(i=0; *str && i<MAX_NUMBERS; ++i)
{
numbers[i] = strtol(str, &end, 10);
str = end;
};
Though it maybe that you get a trailing 0 in your numbers array if the string has whitespace after the last number.

Resources