atoi

N

Nezhate

Hi all,
Can you help me? Why this warning appears in the next simple code ?
warning: passing argument 1 of ‘atoi’ makes pointer from integer
without a cast.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int i;
char line[100];

int main ()
{
printf("Enter line:\n");
fgets(line,sizeof(line),stdin);
line[strlen(line)-1]='\0';
for (i=0;i<strlen(line);i++)
{
printf("line[%d]=%d\n",i,atoi(line));
}
exit(0);
}

when excuting:
$ ./test
Enter line:
this is a test
Segmentation fault
 
S

santosh

Nezhate said:
Hi all,
Can you help me? Why this warning appears in the next simple code ?
warning: passing argument 1 of ?atoi? makes pointer from integer
without a cast.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int i;
char line[100];

int main ()
{
printf("Enter line:\n");
fgets(line,sizeof(line),stdin);
line[strlen(line)-1]='\0';

This is not needed. Fgets will always terminate the input with a null
character.
for (i=0;i<strlen(line);i++)
{
printf("line[%d]=%d\n",i,atoi(line));


The function atoi expects a char * parameter. Here you are passing it
char objects which are really just integers in C. That's what your
compiler is complaining about.
}
exit(0);
}

when excuting:
$ ./test
Enter line:
this is a test
Segmentation fault

I think you may want something like this:

#include <stdio.h>
#include <stdlib.h>
#define LINE_SIZE 16

int main(void) {
char input[LINE_SIZE];
int val;

puts("Enter an integer:");
if (fgets(input, sizeof input, stdin) == NULL) exit(EXIT_FAILURE);
val = atoi(input);
printf("You entered: %s\nAtoi returned: %d\n", input, val);
return 0;
}

But be aware that atoi provides no error detection or recovery. If you
pass it wrong or out-of-range numeric strings, it will merrily invoke
undefined behaviour. The strto* set of functions like strtol, strtoul,
etc., are much more robust. See your C library documentation for all
these functions.
 
B

Barry Schwarz

Hi all,
Can you help me? Why this warning appears in the next simple code ?
warning: passing argument 1 of ‘atoi’ makes pointer from integer
without a cast.

This is one of the few diagnostics that really is self explanatory.
atoi requires that the argument be a pointer to char. Your argument
is line. Since line is an array of char, line is obviously one
of the char in the array. You should recognize that char is a
completely different thing than a pointer to char. They are not
interchangeable nor is there any implicit conversion between them.
Hence the compiler is obligated to tell you that your are calling atoi
with an illegal type.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int i;
char line[100];

int main ()
{
printf("Enter line:\n");
fgets(line,sizeof(line),stdin);
line[strlen(line)-1]='\0';
for (i=0;i<strlen(line);i++)
{
printf("line[%d]=%d\n",i,atoi(line));


You appear to be printing out the elements of line one char at a time.
Go back to your reference and convince yourself that atoi is not the
function to convert an individual char to int. You should be able to
determine how atoi knows where to start looking for characters (yes
the plural is a hint) and how atoi knows when to stop looking.

Then ask yourself what, IF ANYTHING (that is another hint), you need
to do to line so that printf can print it as an int.
}
exit(0);
}

when excuting:

Until you are a lot more experienced, it is a waste of time to execute
code that did not compile cleanly.
$ ./test
Enter line:
this is a test
Segmentation fault

Believe it or not, this is one of the preferred manifestations of
undefined behavior.


Remove del for email
 
N

Nezhate

Thanks to all for their help.
I found the solution. In order to not use atoi function with an array
of characters, I wrote a small function, which uses the Ascii code of
character under test. Here it is:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int char2int(char c)
{
int num;
if ((c>='0')&&(c<='9'))
num=c-'0';
else
{
printf("Character \"%c\" is not a number\n",c);
num=0;
}
return (num);
}

int main ()
{
int i;
char line [100];
printf ("Enter a line to test\n");
fgets(line,sizeof(line),stdin);
line[strlen(line)-1]='\0';
for (i=0;i<strlen(line);i++)
{
int r=char2int(line);
printf("line[%d]=%d\n",i,r);

}
exit(0);
}
 
B

Barry Schwarz

Thanks to all for their help.
I found the solution. In order to not use atoi function with an array
of characters, I wrote a small function, which uses the Ascii code of
character under test. Here it is:

Your code does not use the ASCII values of the characters. It is
guaranteed to work on any character system which complies with the
requirement for digits to be encoded sequentially. This includes
EBCDIC used on IBM mainframes.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int char2int(char c)
{
int num;
if ((c>='0')&&(c<='9'))
num=c-'0';
else
{
printf("Character \"%c\" is not a number\n",c);
num=0;
}
return (num);

return is a statement, not a function. It does not require
parentheses.
}

int main ()
{
int i;
char line [100];
printf ("Enter a line to test\n");
fgets(line,sizeof(line),stdin);
line[strlen(line)-1]='\0';
for (i=0;i<strlen(line);i++)
{
int r=char2int(line);
printf("line[%d]=%d\n",i,r);


If you have the character '5', this will print the integer 5. The
question is, why convert at all? You could simply print the character
itself. Replace these two lines with
printf("line[%d]=%c\n",i,line);

If the error message from char2int is important, the replacement would
be
if (isdigit(line))
printf("line[%d]=%c\n",i,line);
else
printf("Character \"%c\" is not a number\n",c);
}
exit(0);
}


Remove del for email
 
B

Ben Bacarisse

Barry Schwarz said:
Your code does not use the ASCII values of the characters. It is
guaranteed to work on any character system which complies with the
requirement for digits to be encoded sequentially.

In steps of one, starting with '0' and increasing to '9'.
This includes
EBCDIC used on IBM mainframes.

and all conforming C implementations.

It is a small clarification, but it seems worth the bandwidth.
 
K

Keith Thompson

Nezhate said:
Thanks to all for their help.
I found the solution. In order to not use atoi function with an array
of characters, I wrote a small function, which uses the Ascii code of
character under test. Here it is:

I have a bit of constructive criticism.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int char2int(char c)
{
int num;
if ((c>='0')&&(c<='9'))

The extra parentheses really aren't necessary. The >= and <=
operators bind more tightly than &&. I'd write this with some extra
whitespace as:

if (c >= '0' && c <= '9')

or maybe:

if (c>='0' && c<='9')

Or you could add "#include <ctype.h>" and use isdigit() here.

As it happens, the method you use here is guaranteed to work, but the
corresponding technique ((c>='a')&&(c<='z')) is *not* guaranteed to
work for letters. It's a good idea to get into the habit of using the
<ctype.h> functions for character classification.

Note that isdigit() expects an int argument that's representable as an
unsigned char, so you'd need to write:

if (isdigit((unsigned char)c))
num=c-'0';
else
{
printf("Character \"%c\" is not a number\n",c);

It doesn't matter so much for a small program like this, but in
general utility functions shouldn't print error messages. (Also,
error messages should usually go to stderr, not stdout.) Here, you
know exactly how the function will be used, but you don't always have
that luxury, so you want to give the caller a bit more flexibility.
Use some method to tell *the caller*, not the user, that there was an
error, and let the caller handle it.

num=0;
}
return (num);

The parentheses aren't necessary.

Here's how I'd write the char2int function:

/*
* Returns value of a digit ('5' -> 5, for example).
* Returns -1 for a non-digit.
*/
int char2int(char c)
{
if (isdigit((unsigned char)c)) {
return c - '0';
}
else {
return -1;
}
}
int main ()

Make this "int main(void)". "int main()" is almost certainly ok, but
it's better to be explicit.
{
int i;
char line [100];
printf ("Enter a line to test\n");
fgets(line,sizeof(line),stdin);
line[strlen(line)-1]='\0';

Here you replace the '\n' left in the string by fgets() with '\0'.
But fgets() doesn't *always* leave a '\n' in the string. (Exercise:
figure out under what circumstances it doesn't.)
for (i=0;i<strlen(line);i++)

Here you have a fairly nasty inefficiency, though it's not something
that's going to make any visible difference in this program. You call
strlen(line) every time through the loop. The strlen() function has
to scan the string from the beginning to find the terminating '\0'
character every time it's called. You've turned an O(N) algorithm
into an O(N**2) algorithm. Since the value of strlen(line) doesn't
change during the loop, this is wasteful.

Save the value of strlen(line) in a variable and test it.

Note that you do change the length of the string when you replace the
'\n' with '\0'. If you want to be just a little bit tricky, you could
do something like this:

size_t len;
...
fgets(line,sizeof(line),stdin);
len = strlen(line);

line[strlen(line)-1] = '\0';
len --;
{
int r=char2int(line);
printf("line[%d]=%d\n",i,r);


Note that you don't really need "r"; you could write:

printf("line[%d]=%d\n", i, char2int(line)));

But if you're planning to use "r" for other things as you modify the
code, it's good to have it.
}
exit(0);

"return 0;" would also work here.
 
C

Chris Dollin

Keith said:
or maybe:

if (c>='0' && c<='9')

Or you could add "#include <ctype.h>" and use isdigit() here.

If not using `isdigit` I'd write it as

if ('0' <= c && c <= '9') ...

so that the two occurences of `c` were next to each other
(making it obvious that it's the same `c`).

It's a shame that C lost BCPL's

'0' <= c <= '9'

(also a shame that in at least one BCPL compiler the generated
code for this was buggy if `c` had side-effects).
 
S

Sri Harsha Dandibhotla

Thanks to all for their help.
I found the solution. In order to not use atoi function with an array
of characters, I wrote a small function, which uses the Ascii code of
character under test. Here it is:

Your code does not use the ASCII values of the characters. It is
guaranteed to work on any character system which complies with the
requirement for digits to be encoded sequentially. This includes
EBCDIC used on IBM mainframes.




#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int char2int(char c)
{
int num;
if ((c>='0')&&(c<='9'))
num=c-'0';
else
{
printf("Character \"%c\" is not a number\n",c);
num=0;
}
return (num);

return is a statement, not a function. It does not require
parentheses.
int main ()
{
int i;
char line [100];
printf ("Enter a line to test\n");
fgets(line,sizeof(line),stdin);
line[strlen(line)-1]='\0';
for (i=0;i<strlen(line);i++)
{
int r=char2int(line);
printf("line[%d]=%d\n",i,r);


If you have the character '5', this will print the integer 5. The
question is, why convert at all? You could simply print the character
itself. Replace these two lines with
printf("line[%d]=%c\n",i,line);



maybe the simple code was just to check if the function worked
correctly?
If the error message from char2int is important, the replacement would
be
if (isdigit(line))
printf("line[%d]=%c\n",i,line);
else
printf("Character \"%c\" is not a number\n",c);


}
exit(0);
 
K

Keith Thompson

CBFalconer said:
I approve of the extra spaces, and also the extra parentheses.
They make the expression action completely understandable at first
glance.

So you prefer this?

if ((c >= '0') && (c <= '9'))

This is a matter of taste. I'm not going to disagree with you, but I
will say that my own taste differs. The fact that the relational
operators bind more tightly than "&&" seems to me to be sufficiently
obvious that the extra parentheses are IMHO unnecessary. Similarly, I
wouldn't use:

x = (y + z);

because it's even more obvious that "+" binds more tightly than "=".

Again, I'm not saying I disagree, merely that my own taste differs on
this point (and anyone *reading* C code needs to be able to deal with
either style).
Note that making a practice of separating all operators with blanks
avoids accidentally creating such things as a '+=' operator.

How would that happen? I don't believe there's any context in which
the tokens "+" and "=" can be adjacent in a legal program. (In early
pre-K&R C, the "-=" token was spelled "=-", which meant that "x=-1"
would decrement x rather than assigning the value -1 to it; it was
changed to "=-" for exactly this reason.)
 
K

Keith Thompson

CBFalconer said:
It can turn faulty code into error-free (according to compiler)
code.

Um, how? How can leaving out blanks accidentally create a "+="
operator? Can you provide an example?
Another nuisance area is code using ++ and --.

How so?
 
H

Harald van Dijk

Um, how? How can leaving out blanks accidentally create a "+="
operator? Can you provide an example?

If you want to write

*p++ = 3;

and you accidentally write

*p+ = 3;

the compiler will complain.

If you want to write

*p++=3;

and you accidentally write

*p+=3;

the compiler won't complain.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top