atoi function in K&R C book - c

I have some problems with an example of atoi() function from K&R C 2nd edition. Only characters from 0 to 9 should be used. But somewhere in the logic of my program I do something wrong.
So in there is this function:
#include <stdio.h>
int atoi(char s[]);
int main()
{
int i;
char ch;
char co[50];
int ci[50];
while(ch != EOF )
{
for(i=0;i<50-1 && (ch=getchar()) != EOF && ch != '\n';++i)
{
co[i] = ch;
/*ci[i] = atoi(co[i]);*/ /*bugged*/
ci[i] = atoi(co);
printf("%d \n",ci[i]);
}
if(ch == '\n')
{
co[i] = '\n';
}
++i;
co[i] = '\0';
}
return(0);
}
/* as in the book: */
/* atoi: convert s to integer */
int atoi(char s[])
{
int i, n;
n = 0;
for(i = 0; s[i] >= '0' && s[i] <= '9'; ++i)
{
n = 10 * n + (s[i] - '0');
}
return(n);
}
Here are the errors I'm getting:
|In function 'main':
19|warning: passing argument 1 of 'atoi' makes pointer from integer without a cast [enabled by default]
3|note: expected 'char *' but argument is of type 'char'
||=== Build finished: 0 errors, 1 warnings (0 minutes, 0 seconds) ===|

The
(s[i] = '0')
should read
(s[i] - '0')
(note the minus instead of the equals sign).
This converts the characters '0'..'9' to the numeric values 0..9.
You are also not calling atoi() correctly. It takes a string, not a char. You should probably call it from outside the loop.
And ch isn't the right type (it should be int).

atoi(); function need pointer to string. char* that is the reason warning warning: passing argument 1 of 'atoi' makes pointer from integer without typecase
you declare co like: char co[50]; but calls atoi(co[i]); this is wrong,
notice it says int not char.
an example like:
atoi("1"); is valid but atoi('1'); not valid.
so even co is like "12345678" then atoi(co) correct but atoi(co[i]) not correct.

printf("%c = ",co[i]);
ci[i] = atoi(co[i]);
printf("%d \n",ci[i]);
You are trying to convert a char to int, but a char is an integer value. All you need is
printf("%c = %d\n", co[i], co[i]);
if what you want is the decimal value of the char. If what you're trying to do is convert an ASCII digit to an integer, then
printf("%c = %d\n", co[i], co[i] - '0');
will do.

Related

How do I get my integer arithmetic into a long long?

As part of exercise 2-3 in Ritchie and Kernighan's C programming language, I've written a program that converts hexadecimal inputs into decimal outputs. I want it to be able to handle larger numbers, but it seems to be doing integer arithmetic somewhere. When you enter something like "DECAFCAB" it spits out a large negative int. I figured out that I need to add the "LL" suffix to my literals, which I did, but it's still not working. Any help please? Sorry if this is a dumb question or a typo, but I've been at it for an hour and can't figure it out. :(
#include <stdio.h>
#define MAX_LINE 1000
void getline(char s[])
{
int i;
char c;
for(i = 0; i < MAX_LINE-1 && (c=getchar()) != EOF && c != '\n'; ++i)
s[i] = c;
s[i] = '\0';
printf("\n%s", s);
}
long long htoi(char s[]) // convert the hex string to dec
{
long long n = 0;
int i = 0;
if(s[i] == '0') // eat optional leading Ox or OX
++i;
if(s[i] == 'x' || s[i] == 'X')
++i;
while(s[i] != '\0')
{
if((s[i] >= '0' && s[i] <= '9'))
n = 16LL * n + (s[i] - '0'); // here is the arithmetic in question
else if(s[i] >= 'A' && s[i]<= 'F')
n = 16LL * n + (s[i] - 'A' + 10LL);
else if(s[i] >= 'a' && s[i] <= 'f')
n = 16LL * n + (s[i] - 'a' + 10LL);
else {
printf("\nError: Encountered a non-hexadecimal format: the '%c' character was unexpected.", s[i]);
printf("\nHexadecimal numbers can begin with an optional 0x or 0X only, and contain 0-9, A-F, and a-f.\n\n");
return -1;
}
++i;
}
return n;
}
main()
{
char input[MAX_LINE];
long long hex_output;
while(1){
getline(input);
hex_output = htoi(input);
if(hex_output >= 0)
printf("\nThe value of the hexadecimal %s is %d in decimal.\n\n", input, hex_output);
}
}
You told printf to expect an int when you made the placeholder %d. To make it expect (and therefore read the entirety of a) long long, modify it to %lld.
The reason it looks like a plain int is that with varargs functions like printf, it doesn't know what the argument sizes are, and the format string is the only way to figure it out. When you say to expect plain int, it reads sizeof(int) bytes from the argument, not sizeof(long long) bytes (it's not necessarily byte-oriented, but that's how much data is read), and (on a little endian system with 4 byte int and 8 byte long long) you see (roughly) the result of the argument with the top 4 bytes masked off.
The problem you are experiencing comes from treating a (conventionally) "unsigned" hexadecimal integer value as "signed". Resorting using to a larger built-in data type will get you past the problem with going from 31 to 32 bits, but this masks the actual problem. (If you extend to 64 bits, you will encounter the same problem and be back asking, "why doesn't this work.")
Better is to write code that doesn't require ever wider registers. There will always be a maximum width, but the answer to this OP is to use an "unsigned long".
#include <stdio.h>
unsigned long htoi( char s[] ) { // convert the hex string to dec
unsigned long n = 0;
int i = 0;
if(s[i] == '0') // eat optional leading Ox or OX
++i;
if(s[i] == 'x' || s[i] == 'X')
++i;
for( ; s[i]; i++ ) {
unsigned int dVal = 0; // don't copy/paste complex statements.
if((s[i] >= '0' && s[i] <= '9'))
dVal = s[i] - '0'; // simple
else if(s[i] >= 'A' && s[i]<= 'F')
dVal = s[i] - 'A' + 10; // simple
else if(s[i] >= 'a' && s[i] <= 'f')
dVal = s[i] - 'a' + 10; // simple
else {
// less verbose
printf("\nError: '%c' unexpected.", s[i] );
return 0; // NB: Notice change!!
}
n = (16 * n) + dVal; // simple...
}
return n;
}
int main() {
// simplified, stripping out user input.
char *hexStr = "0xDECAFCAB";
unsigned long hex_output = htoi( hexStr );
// Notice the format specifier to print an ordinary (unsigned) long
printf( "\nThe value of the hexadecimal %s is %u in decimal.\n\n", hexStr, hex_output );
return 0;
}
The value of the hexadecimal 0xDECAFCAB is 3737844907 in decimal.
When K&R wrote the original book, there was no such thing as "long long", but there was "unsigned long".

Passing character array to a function returns warning

Currently completing my C homework for the week and i'm messing about with pointers for the first time properly.
We are told to create a main function to deal with our readLine function thats premade for us (we edit a few things, like the if statement in the while loop).
When trying to compile i am given the error "/usr/include/stdio.h:356:43: note: expected ‘const char * restrict’ but argument is of type ‘int’
356 | extern int printf (const char *__restrict __format, ...);
What would i have to do to fix this? I think its something to do with how im calling readLine. Thanks!
#include <stdio.h>
int readLine(char *s, int MAX){
char c;
int i = 0;
while ((c = getchar()) != '\n' && i<MAX){
if (*s >= MAX){
printf("input too long!");
return -1;
}
c = *(s+i);
}
s[i] = '\0';
return i;
}
int main(){
int MAX = 20;
char s[MAX];
printf(readLine(s, MAX));
}
The function returns an integer but you are going to output a string. So write
readLine(s, MAX);
puts( s );
Also this if statement
if (*s >= MAX){
does not make sense.
And instead of
c = *(s+i);
you have to write
*(s+i) = c;
And within the while loop you need to increase the variable i.

cs50 credit.c stops working when reading input from a function, pointer?

I've been teaching myself some C and did the problems from the cs50 course. My program works fine but I tried to make it simpler and divide it in as many functions as possible. Everything worked except the readInput function. I'm pretty sure it has to do with how the pointer from the array works and I have tried to do something someone suggested here on SO but I get a segmentation fault, I have tried different ways to do this but everything leads to more faults. Any tips would be highly appreciated!
void readInput(int **digits){
char c; // char to get the digits
int position = 0; // pos in the array
while ((c = getchar()) != '\n') {
if (c >= '0' && c <= '9') {
(*digits)[position] = c - '0';
position++;
}
}
}
int main(int argc, char const *argv[])
{
printf("Please enter your credit card number\n");
int digits[16];
intitializeArray(16, digits);
readInput(&digits);
int length = getLength(digits);
int resultSecondDigits = getValueSecondDigits(length, digits);
int resultFirstDigits = getValueFirstDigits(length, digits);
checkValidity(resultFirstDigits+resultSecondDigits, digits);
return 0;
}
Read the compiler warnings properly it says
pembroke11.c:2:6: note: expected ‘int **’ but argument is of type ‘int
(*)[16]’ void readInput(int **digits){
It should be like this
void readInput(int (*digits)[16]){
/* some code */
}
OR
No need to pass address of digits to readInput() function, just pass pass the array name.
void readInput(int *digits){
int c; // char to get the digits
int position = 0; // pos in the array
while ((c = getchar()) !='\n') { /* type of c should be int as getchar() returns int */
if (c >= '0' && c <= '9') {
digits[position] = c - '0';
printf("%d\n", digits[position]);
position++;
}
}
}

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.

C - error conflicting types for function

I'm new to C. I'm trying to get a lot of text from the user and count the number of words, characters, lines, whitespaces and letters. This is what I've done:
#include <ctype.h>
#include <stdio.h>
int main(void)
{
char c = getchar();
char previousc;
int charcount = 0;
int wordcount = 0;
int whitespacecount = 0;
int linecount = 0;
int lettercount = 0;
while(c != EOF)
{
if(isLetter(c) == 1) lettercount++;
if(isWhitespace(c) == 1)
{
whitespacecount++;
if(isWhitespace(previousc) == 0) wordcount++;
}
if(c == "\n") linecount++;
previousc = c;
c = getchar();
charcount++;
}
printf("Character Count: %d\n Word Count: %d\n Whitespace Count: %d\n Letter Count: %d\n Line Count: %d\n", charcount, wordcount, whitespacecount, linecount, lettercount);
}
int isLetter(char c) // 1 for true, 0 for false.
{
// instead of writing tons of if's
if(isalpha(c) > 0)
return 1;
return 0;
}
int isWhitespace(char c) // 1 for true, 0 for false.
{
if(c == "\n" || c == " " || c == " ") return 1;
return 0;
}
But I get so many errors and warnings I'm just lost...
program2.c: In function ‘main’:
program2.c:20: warning: comparison between pointer and integer
program2.c: At top level:
program2.c:28: error: conflicting types for ‘isLetter’
program2.c:28: note: an argument type that has a default promotion can’t match an empty parameter name list declaration
program2.c:14: error: previous implicit declaration of ‘isLetter’ was here
program2.c:35: error: conflicting types for ‘isWhitespace’
program2.c:35: note: an argument type that has a default promotion can’t match an empty parameter name list declaration
program2.c:15: error: previous implicit declaration of ‘isWhitespace’ was here
program2.c: In function ‘isWhitespace’:
program2.c:36: warning: comparison between pointer and integer
program2.c:36: warning: comparison between pointer and integer
program2.c:36: warning: comparison between pointer and integer
I googled the different errors but didn't find a solution that solves my problem.
Can you help me a bit?
Thanks.
For
program2.c:20: warning: comparison between pointer and integer
Change
if(c == "\n")
to
if(c == '\n')
For
program2.c:28: error: conflicting types for ‘isLetter’
program2.c:28: note: an argument type that has a default promotion can’t match an empty parameter name list declaration
program2.c:14: error: previous implicit declaration of ‘isLetter’ was here
program2.c:35: error: conflicting types for ‘isWhitespace’
program2.c:35: note: an argument type that has a default promotion can’t match an empty parameter name list declaration
program2.c:15: error: previous implicit declaration of ‘isWhitespace’ was here
Define prototypes for your functions.
int isLetter(char c);
int isWhitespace(char c);
For
program2.c: In function ‘isWhitespace’:
program2.c:36: warning: comparison between pointer and integer
program2.c:36: warning: comparison between pointer and integer
program2.c:36: warning: comparison between pointer and integer
Change
if(c == "\n" || c == " " || c == " ") return 1;
to
if(c == '\n' || c == ' ' || c == '\t')
Start with the first error/warning, fix it and then work your way down one by one always compiling after each change. Often, you will find, getting rid of an error/warning on a line also gets rid of others in subsequent lines.
Line 20:
if(c == "\n") linecount++;
gives the warning
program2.c:20: warning: comparison between pointer and integer
c is a char (internally converted to an integer before the comparison); "\n" is an array[2] of char (internally converted to char * before the comparison).
That's why the compiler complains about comparing an integer and a pointer.
You need to compare c to a character (both will get internally converted to integers)
if(c == '\n') linecount++;
Declare the following functions before calling them (i.e., above function main):
int isLetter(char c);
int isWhitespace(char c);
In function main:
Replace the variable-declaration char c with int c
Replace the function-call isLetter(c) with isLetter((char)c)
Replace the function-call isWhitespace(c) with isWhitespace((char)c)
Replace the variable-assignment previous = c with previous = (char)c
Replace the conditional-statement if (c == "\n") with if ((char)c == '\n')
The reason for int c, is that function getchar returns int in order support the EOF indicator.
In function isWhitespace, change the conditional-statement to:
if (c == ' ' || c == '\n' || c == '\r' || c == '\t')
EOF is an integer value which indicate the end of input. It's a value such that for any character ch, ch == EOF is always false. Therefore, you should always compare a value of int type with EOF, not char type. It's working on your machine because the char type is implemented as signed char but on machines where char type is unsigned char, this won't.
Now coming to the warnings and errors
The scope of a function is from the point of its definition or declaration till the end of the program. You are calling the functions like isLetter in main before they have been declared.
"\n" is a string literal, not a character. So are " " and " ". The string literal here evaluates to a pointer to its first element and you are comparing this pointer with a character - a different type. You should, instead, compare with '\n', ' ', '\t' respectively.
you have to declare the function header before using it in the main, for example:
int isLetter(char c);
int main(void){
char c = getchar();
char previousc;
int charcount = 0;
int wordcount = 0;
int whitespacecount = 0;
int linecount = 0;
int lettercount = 0;
while(c != EOF)
{
if(isLetter(c) == 1) lettercount++;
if(isWhitespace(c) == 1)
{
whitespacecount++;
if(isWhitespace(previousc) == 0) wordcount++;
}
if(c == "\n") linecount++;
previousc = c;
c = getchar();
charcount++;
}
printf("Character Count: %d\n Word Count: %d\n Whitespace Count: %d\n Letter Count: %d\n Line Count: %d\n", charcount, wordcount, whitespacecount, linecount, lettercount);}
that will fix the conflicting types error.
but also you'll have to change " " to ' ' if you are checking on characters.

Resources