What should char function return in C? - 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.

Related

C program to remove consecutive repeated characters from string

The code: https://pastebin.com/nW6A49ck
/* C program to remove consecutive repeated characters from string. */
#include <stdio.h>
int main() {
char str[100];
int i, j, len, len1;
/* read string */
printf("Enter any string: ");
gets(str);
/* calculating length */
for (len = 0; str[len] != '\0'; len++);
/* assign 0 to len1 - length of removed characters */
len1 = 0;
/* Removing consecutive repeated characters from string */
for (i = 0; i < (len - len1);) {
if (str[i] == str[i + 1]) {
/* shift all characters */
for (j = i; j < (len - len1); j++)
str[j] = str[j + 1];
len1++;
} else {
i++;
}
}
printf("String after removing characters: %s\n", str);
return 0;
}
The problem: Lets say I have the string 'Hello' as an input..I want the two ls to be both removed (not only 1)... Same for 'Helllo' (I want the 3 ls to be removed and not just the 2 ls)... How can I do that?
if (str[i] == str[i + 1]) {
/* shift all characters */
for (j = i; j < (len - len1); j++)
str[j] = str[j + 1];
len1++;
}
Maybe I can count the times every character is repeated and then in line 28 replace 1 with the the times a character is repeated? But how can I implement this to the code?
You could make a function to remove the ranges with equal characters by copying character by character to a separate pointer in the string that you do not step forward if repeating characters are found:
void foo(char *str) {
for(char *wr = str; (*wr = *str) != '\0';) { // copy until `\0` is copied
++str; // step to the next character
if(*wr != *str) { // if the next char is not equal to `*wr`
++wr; // step `wr` forward to save the copied character
} else do {
++str; // `*wr == *str`, so step `str` forward...
} while(*wr == *str); // ...until a different character is found
}
}
*wr = *str copies the current character str is pointing at to where wr is currently poining. The != '\0' check makes the loop end when \0 (the null terminator) has been copied.
After that str is increased to point at the next character.
If the next character is not equal to the one which was just copied, increase wr to save that copied character.
If the next character was indeed equal to the one being copied, don't increase wr to let it be overritten by the next character being copied and step str forward until a different character is found.
Demo
A dense version doing exactly the same thing:
void foo(char *str) {
for(char *wr = str; (*wr = *str) != '\0';) {
if(*wr != *++str) ++wr;
else while(*wr == *++str);
}
}
This code snippet should remove all consecutive characters out of your string (note that some C compilers won't let you declare variables within the internal blocks):
for (int i=0; i<len; i++) {
int j = i, repeats = 1;
while (j < len-1 && str[j] == str[++j])
{
repeats++;
}
if (repeats > 1) {
for (j = i; j < len - repeats; j++)
{
str[j] = str[j + repeats];
}
len -= repeats;
i--;
str[len] = '\0';
}
}
Links are discouraged, instead, you should post the contents of link. Also, for such kind of problem, I will suggest first come up with an appropriate algorithm and then implement it. At time, you will find it much more easier than taking someone else's code and making changes to it make it work as per your need.
Algorithm:
Step I: Record the position where the letter to be written in the string (calling this position - P). Initially, it will be start of string.
Step II: If current processing character is same as it's next character, then
Dont make any change in P.
Set a flag to skip next character (calling this flag - F).
Step III: If current processing character and next character are different, then
If flag F is set, skip this character, reset flag F and don't change P.
If flag F is not set then write this character at position P in the string and set P to next position.
Step IV: Move to next character in the string and go to Step II.
Implementation:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void remove_all_consecutive_dup_chars (char * pstr) {
if (pstr == NULL) {
printf ("Invalid input..\n");
return;
}
/* Pointer to keep track of position where next
* character to be write.
*/
char * p = pstr;
int skip_letter = 0;
for (unsigned int i = 0; pstr[i] ; ++i) {
/* Using tolower() to identify the consecutive characters
* which are same and only differ in case (upper/lower).
*/
if ((tolower (pstr[i]) == tolower (pstr[i + 1]))) {
skip_letter = 1;
continue;
}
if (skip_letter) {
skip_letter = 0;
} else {
*p++ = pstr[i];
}
}
/* Add the null terminating character.
*/
*p = '\0';
}
int main (void) {
char buf[256] = {'\0'};
strcpy (buf, "WELL, well, welLlLl....");
printf ("%s ----> ", buf);
remove_all_consecutive_dup_chars (buf);
printf ("%s\n", buf);
strcpy (buf, "Hello");
printf ("%s ----> ", buf);
remove_all_consecutive_dup_chars (buf);
printf ("%s\n", buf);
strcpy (buf, "Helllo");
printf ("%s ----> ", buf);
remove_all_consecutive_dup_chars (buf);
printf ("%s\n", buf);
strcpy (buf, "aAaaaA ZZz");
printf ("%s ----> ", buf);
remove_all_consecutive_dup_chars (buf);
printf ("%s\n", buf);
return 0;
}
Output:
# ./a.out
WELL, well, welLlLl.... ----> WE, we, we
Hello ----> Heo
Helllo ----> Heo
aAaaaA ZZz ---->
EDIT:
In above program, I have used tolower() with an assumption that the string, passed as argument to remove_all_consecutive_dup_chars(), will contain only alphabets - [A - Z]/[a - z] and space character.
Note that, tolower() can result in UB if pstr[i] < 0. If you use tolower(), just make sure that argument you pass to tolower() shall be representable as an unsigned char.

How to find number of occurrences in array of chars in C?

I am trying to enter a word, and get how many times the letters were typed.
Say my input is "hello"
my output would be: h = 1, e = 1 l = 2 etc.
I am very close to getting it right, but I have a small issue with this code:
#include <stdio.h>
#include <string.h>
void find_frequency(char s[], int count[]) {
int c = 0;
while (s[c] != '\0') {
if (s[c] >= 'a' && s[c] <= 'z' )
count[s[c]-'a']++;
c++;
}
}
int main()
{
char string[100];
int c, count[26] = {0};
printf("Input a string\n");
gets(string);
find_frequency(string, count);
printf("Character Count\n");
for (c = 0 ; c < 26 ; c++)
if(count[c] > 0)
printf("%c : %d\n", c + 'a', count[c]);
return 0;
}
This code does half of the job, but not all.
It's output is in alphabetical order. How can i change it to give me an output of just the chararray that is input?
As Ry- suggested in this comment you could iterate back over the original string and use the chars as indices into your frequency table. Something like the following:
int len_string = strlen(string);
for (c=0; c<len_string; c++) {
char ch = string[c];
printf("%c: %d, ", ch, count[ch-'a']);
}
This won't completely match your expected output, since this code will output l: 2 twice, but that raises the question:
What is your expected output when you have a string like abba? a:2, b:2? a:1, b:2, a:1? a: 2, b:2, a:2? It's hard to help when you ask such an ambiguous question.
#include <stdio.h>
#include <string.h>
size_t ASCIIfreq[256];
void CountASCII(void *buff, size_t size)
{
unsigned char *charsptr = buff;
memset(ASCIIfreq, 0, sizeof(ASCIIfreq));
while(size--)
{
ASCIIfreq[*charsptr++]++;
}
}
void print(int printall)
{
for(size_t index = 0; index < 256; index++)
{
if(ASCIIfreq[index] || printall)
{
printf("The %03zu (0x%02zx) ASCII - '%c' has occured in the buffer %zu time%c\n",
index, index, (index > 32 && index < 127) ? (char)index : ' ',
ASCIIfreq[index], ASCIIfreq[index] == 1 ? ' ' : 's');
}
}
}
int main()
{
char teststring[] = "i am trying to enter a word, and get how many times the letters were typed. Say my input is \"hello\" my output would be: h = 1, e = 1 l = 2 etc.I am very close to getting it right, but i have a small issue with this code";
CountASCII(teststring, sizeof(teststring));
print(0);
return 0;
}
It's not clear what you mean by:
How can i change it to give me an output of just the chararray that is input?
Because that's exactly what you're doing in any case: Inputting a char array to the function; which is updated with numbers alphabetically; and later output as is.
So I'm guessing that you want to output the counts in the same order that each char was first encountered?
Solution
This will require a bit more work. You could keep a second array tracking the the order each character is encountered within find_frequency. But then that simple clean function starts doing too much.
So consider rather tweaking how you do the output:
void output_frequency(char s[], int count[]) {
int c = 0;
//loop s for the output
while (s[c] != '\0') {
if (s[c] >= 'a' && s[c] <= 'z' ) {
//found a character, report the count only if not reported before
if (count[s[c]-'a'] > 0) {
printf("%c : %d\n", s[c], count[s[c] - 'a']);
count[s[c]-'a'] = 0; //so you don't report this char again
}
}
c++;
}
}
If you are attempting to get an in-order count instead of a count in alphabetical order, you simply need to coordinate the indexes of your count array with the order of characters in your input buffer. To do that, simply loop over all characters in your input buffer and make a second pass counting the number of times the current character occurs. This will give you an in-order count of the number of times each character occurs, e.g.
#include <stdio.h>
#include <string.h>
#define COUNT 128
#define MAXC 1024
int main (void) {
char buf[MAXC] = ""; /* buffer to hold input */
int count[COUNT] = {0}; /* array holding inorder count */
fputs ("enter string: ", stdout); /* prompt for input */
if (!fgets (buf, MAXC, stdin)) { /* read line into buf & validate */
fputs ("error: EOF, no valid input.\n", stderr);
return 1;
}
/* loop over each character not '\n' */
for (int i = 0; buf[i] && buf[i] != '\n'; i++) {
char *p = buf; /* pointer to buf */
size_t off = 0; /* offset from start of buf */
while ((p = strchr (buf + off, buf[i]))) { /* find char buf[i] */
count[i]++; /* increment corresponding index in count */
off = p - buf + 1; /* offset is one past current char */
}
}
for (int i = 0; count[i]; i++) /* output inorder character count */
printf (i ? ", %c: %d" : "%c: %d", buf[i], count[i]);
putchar ('\n'); /* tidy up with new line */
return 0;
}
(note: strchr is used for convenience to simply find the next occurrence of the current character within the string and then off (offset) is used to start the search with the following character until no other matches in the string are found. You can simply use an additional loop over the characters in the buffer if you like.)
Example Use/Output
$ /bin/charcnt_inorder
enter string: hello
h: 1, e: 1, l: 2, l: 2, o: 1
However, this does recount each character and give the count again if the character is duplicated, (e.g. l: 2, l: 2 for each 'l'). Now it is unclear from:
"my output would be: h = 1, e = 1 l = 2 etc."
what you intended in that regard, but with just a little additional effort, you can use a separate index and a separate array to store the first instance of each character (in say a chars[] array) along with the count of each in your count[] array and preserve your inorder count while eliminating duplicate characters. The changes needed are shown below:
#include <stdio.h>
#include <string.h>
#define COUNT 128
#define MAXC 1024
int main (void) {
char buf[MAXC] = "",
chars[COUNT] = ""; /* array to hold inorder chars */
int count[COUNT] = {0};
size_t cdx = 0; /* add count index 'cdx' */
fputs ("enter string: ", stdout);
if (!fgets (buf, MAXC, stdin)) {
fputs ("error: EOF, no valid input.\n", stderr);
return 1;
}
for (int i = 0; buf[i] && buf[i] != '\n'; i++) {
char *p = buf;
size_t off = 0;
chars[cdx] = buf[i]; /* store in chars array */
if (i) { /* if past 1st char */
int n = i;
while (n--) /* simply check all before */
if (buf[n] == buf[i]) /* if matches current */
goto next; /* bail and get next char */
}
while ((p = strchr (buf + off, buf[i]))) {
count[cdx]++; /* increment count at index */
off = p - buf + 1;
}
cdx++; /* increment count index */
next:; /* goto label to jump to */
}
for (int i = 0; count[i]; i++)
printf (i ? ", %c: %d" : "%c: %d", chars[i], count[i]);
putchar ('\n');
return 0;
}
Example Use/Output
$ /bin/charcnt_inorder2
enter string: hello
h: 1, e: 1, l: 2, o: 1
or
$ ./bin/charcnt_inorder2
enter string: amarillo
a: 2, m: 1, r: 1, i: 1, l: 2, o: 1
Now your 'l' is only reported once with the correct count.
Note, in each example you should do additional validation to insure the entire input fit within your buffer, etc... The count (and chars) array were sized at 128 to cover the entire range of ASCII values. Don't skimp on buffer size. If you explicitly limit your input to UPPERcase or lowercase -- then you can limit your count size to 26, otherwise you need to consider the additional characters and punctuation that will be encountered. The same applies to your input buffer. If you anticipate you max input would be 500 chars, double it (generally to next available power of two, no real requirement for powers of two, but you are likely to see it that way).
Bottom line, I'd rather be 10,000 characters too long that one character too short... leading to Undefined Behavior.
Lastly, as mentioned in my comment never, never, never use gets. It is so insecure it has been removed from the C standard library in C11. Use fgets or POSIX getline instead.
Look things over and let me know if you have further questions.

Swap the 2nd character with the next-to-last

I have to change the 2nd letter with penultimate letter for word with more than 3 letters.
Example i have this string: Alex are mere
The result should be: Aelx are mree
But i get this when i run my program: Axel` aler
This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i,n,j=0;
char text[81],cuv[44],l;
printf("Introduce-ti textul:");
gets(text);
for(i=0;i<strlen(text);i++)
{
if(text[i] != 32) {
cuv[j]=text[i];
j += 1;
} else {
n = strlen(cuv) - 1;
l= cuv[1];
cuv[1]=cuv[n-1];
cuv[n-1]=l;
printf("%s ",cuv);
strcpy(cuv,"");
j=0;
}
}
return 0;
}
First, you do not want to use gets. It was removed from the standard library because it was unsafe, use fgets instead. That being said, all you need to do is tokenize your input string into words, and then if the word is greater than 3 chars, swap the 2nd and next to last characters. One way would be:
#include <stdio.h>
#include <string.h>
#define MAXS 256
#define MAXW 64
int main (void) {
size_t len;
char str[MAXS] = {0};
char word[MAXW] = {0};
char *p = NULL;
fgets (str, MAXS, stdin); /* read input from stdin */
/* tokenize string */
for (p = strtok (str, " "); p; p = strtok (NULL, " \n"))
{
strncpy (word, p, MAXW - 1); /* copy token to word */
if ((len = strlen (word)) > 3) /* if word > 3 */
{
char tmp = word[1]; /* swap 2nd & next to last */
word[1] = word[len-2];
word[len-2] = tmp;
}
printf ("%s ", word);
}
putchar ('\n');
return 0;
}
Use/Output
$ printf "Alex are mere\n" | ./bin/swap2nd
Aelx are mree
or if you wanted to enter the text:
$ ./bin/swap2nd
Alex are mere
Aelx are mree
Second Method Using Start/End Pointers
You can also modify the original string ready be fgets in place by using nothing more than a start-pointer (p below) and end-pointer (ep below) to work your way down the string character-by-character, stopping each time the end-pointer points to a space, tab, or newline and then using the difference between the start and end pointers to check the length of the word and perform the character swap if the length is greater than 3 chars. You can work through each version and compare:
#include <stdio.h>
#define MAXS 256
int main (void) {
char str[MAXS] = {0};
char *p = NULL;
char *ep = NULL;
fgets (str, MAXS, stdin); /* read input from stdin */
p = ep = str;
while (*ep) /* for each char, if a space, tab or newline */
if (*ep == ' ' || *ep == '\t' || *ep == '\n') {
if ((ep - p) > 3) { /* if length > 3 */
char tmp = *(p + 1); /* swap chars */
*(p + 1) = *(ep - 2);
*(ep - 2) = tmp;
}
p = ++ep; /* set p to next word */
}
else
++ep;
printf ("%s\n", str);
return 0;
}
Use/Output
$ ./bin/swap2nd2
Alex are mere
Aelx are mree
Which approach you choose between these two methods, as well as the method posted by Vlad, is largely a matter of taste/choice. All are valid and are just different way of accomplishing the same thing. Let me know if you have questions.
Try the following approach
#include <stdio.h>
int main( void )
{
char s[] = "Alex Chiurtu";
char t[sizeof( s )];
size_t i = 0, j = 0;
do
{
t[i] = s[i];
if ( s[i] != ' ' && s[i] != '\t' && s[i] != '\0' )
{
++j;
}
else if ( j != 0 )
{
if ( j > 3 )
{
char c = t[i-j + 1];
t[i-j+1] = t[i-2];
t[i-2] = c;
}
j = 0;
}
} while ( s[i++] );
puts( s );
puts( t );
return 0;
}
The program output is
Alex Chiurtu
Aelx Ctiurhu
Take into account that function gets is unsafe and is not supported by the C Standard any more.
Also it is a bad idea to use magic numbers like 32. Its meaning is unclear.
In your program array cuv was not zero initialized therefore the following statement
n = strlen(cuv) - 1;
results in undefined behaviour of the program. Also it is not a good idea each time to calculate the length of the string.

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 a int number in 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));

Resources