Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am trying to create my personal atoi function but i doesn't work properly. I don't know why.
void ft_putchar(char c)
{
write(1, &c, 1);
}
int ft_atoi(const char *str)
{
int i;
i = 0;
while (str[i] == 9 || str[i] == 32 || str[i] == 43 || str[i] == 45)
i++;
while (str[i] > 48 && str[i] < 57)
{
ft_putchar(str[i]);
i++;
}
return (0);
}
int main(void)
{
printf("%d", atoi(" 2794ffafsaasf"));
printf("\n%d",ft_atoi(" 2794fsffsf"));
return(0);
}
I kinda works but it doesn't. It gives me a weird result where it even ignores '\n'.
The result it gives me is this.
272794 and a new line.
with only my function it gives me only the number 27.
EDIT:
I have created a new program. But it still doesn't work. It simply can't see digits.
int ft_atoi(const char *str)
{
int i;
int n;
i = 0;
while (str[i] == '\t' || str[i] == ' ' || str[i] == '+' || str[i] == '-')
++i;
n = i;
while (str[n] >= '0' && str[n] <= '9')
{
++n;
}
return(str[n]);
}
Your test for digits has the bounds set wrong. You're testing str[i] > 48 && str[i] < 57, but 48 is the ordinal for the 0 character, and 57 is the ordinal for 9. This means you only consider 1 through 8 inclusive to be numeric digits, and you stop parsing 2794fsffsf at the 9, not at the first f.
Changing the test to str[i] >= 48 && str[i] <= 57 would fix the bounds issue, but would still be less than self-documenting. To make it obvious what you're doing to people who don't have the ASCII tables memorized, you could do:
while ('0' <= str[i] && str[i] <= '9')
or possibly slightly slower but even more obviously with ctype.h:
while (isdigit(str[i]))
You could similarly replace the many non-obvious tests for whitespace ordinal values with isspace(str[i]).
First thing is to ignore leading whitespace. You can do that with i as you're doing, but it's easier to do it by shifting the start of the string forward. I'm guessing that you're reimplementing the standard C library as an exercise. I'm not, so I'm going to make use of the ctype.h functions. Adjust as you like, the basic code remains the same. You should probably write your own ft_isspace and ft_isdigit rather than hard coding the logic.
/* Move str to point at the first non-space character */
while( isspace(str[0]) ) {
str++;
}
Now there's no need for an i to hold your place, you can just work with str[0] and it will be the first non-whitespace character.
Next we need to find and add up our digits. Again, I'll use isdigit. Follow the advice in ShadowRanger's answer if you can't use that function.
The technique is to convert each character to a digit and add it to the total. Since we're reading a number left to right, each new digit multiplies the existing sum by 10. For example, if we had 1234 it would be... 1 then 10 + 2 then 120 + 3 then 1230 + 4.
int num = 0;
while( isdigit(str[0]) ) {
int digit = str[0] - '0';
num *= 10;
num += digit;
str++;
}
Once again I'm manipulating the pointer rather than using an index. This is just to save an integer, and to avoid mixing up two string iteration techniques in a single function.
And, finally, don't forget to return the number!
return num;
What about negative numbers? We need to look for a - before we check for digits, if it's there flip the sign. We also need to handle a + and ignore it.
/* Assume it's positive. */
short sign = 1;
/* Check for a sign. */
switch( str[0] ) {
case '-':
sign = -1;
str++;
break;
case '+':
str++;
break;
}
And then multiply by the sign to flip the result.
return sign * num;
Your code only writes out the numbers - and not all, as pointed out before me (because it excludes '0' and '9' and they should be included!) - to the file identified by 1 (what is maybe the standard output, I don't remember exactly...), and returns 0 as the parameter of the printf. It seems to me a little strange, you only had 27 printed out with your function, but it might be environment(?) specific. (I have not tested it, so it possibly not exactly work as I suppose...)
I've made my version of atoi, hoping I can show where to start / the way how you should do yours:
int nvi9_atoi(const char *s) {
int n = 0, valid = 0, prev = 0;
while(1) { // infinite loop
if (*s == '\0') break; // if it is the end of the string, finish further processing
if (*s >= '0' && *s <= '9') { // check whether the current character is an ascii number
n *= 10; // "move" all previous digits (eg. 1 -> 10, 43 -> 430); if n is 0, this has no effect
if (n >= 0) n += (*s - '0'); // if n is not negative, add the value of the last digit (here is ascii-number "conversion"!)
else n -= (*s - '0'); // if it is negative, the number should be substracted (note eg. if there was -10 so far, and the new number is 2, the new value should be -12, not -8)
if (n > 0 && !valid) { // if n not 0, and there was no digits before it, check if there was a minus sign before
valid = 1; // preventing more check
if (prev == '-') n *= -1; // makes n negative
}
} else if (valid) break; // if there was numbers processed, but the current character is not a number, finish loop
prev = *s; // store current character for minus sign checking of next loop
s++; // move string pointer to the next character
}
return n; // return the converted value
}
It is also untested, so fixes / corrections / improvements are welcome!
This function can even process strings like " sfg afg-65sd1g". In that case the returned value will be -65, because it looks for the first number, then returns.
Related
Your program should read a word from the input and then sort the letters of the word alphabetically (by their ASCII codes). Next, your program should iterate through the letters of the word and compare each letter with the one following it. If these equal each other, you increase a counter by 1, making sure to then skip ahead far enough so that letters that occur more than twice are not counted again. You may assume that the word you read from the input has no more than 50 letters, and that the word is all lowercase.
I wrote a program and get these results:
apple gives me 1
erroneousnesses gives 5,
but taylor should give me 0 however it gives 1.
How can I make yup, taylor and other words with non-repeating alphabets give me 0?
Here is my code:
#include <stdio.h>
int main(void) {
char string[51];
int c = 0, count[26] = { 0 }, x = 0;
scanf("%s", string);
while (string[c] != '\0') {
if (string[c] >= 'a' && string[c] <= 'z') {
x = string[c] - 'a';
count[x]++;
}
c++;
}
printf("%d", count[x]);
return 0;
}
There are multiple problems in your code:
scanf("%s", string); may cause a buffer overflow if the input is longer than 50 bytes.
Furthermore, you do not test the return value to check for invalid or missing input.
counting the number of occurrences of each letter is an alternative approach to the stated problem, and OK if you are only graded based on the program output. However be aware that the program does not implement what the assignment explicitly mandates and the value you output is incorrect anyway.
the output value should be the number of counts that are >= 2. Printing the value of count[x] is meaningless.
Here is a modified version:
#include <stdio.h>
int main() {
char str[51];
int dup = 0;
int count['z' - 'a' + 1] = { 0 };
if (scanf(" %50[a-z]", str) == 1) {
for (int i = 0; str[i] != '\0'; i++) {
if (++count[str[i] - 'a'] == 2)
dup++;
}
printf("%d\n", dup);
}
return 0;
}
to answer your specifc question
printf("%d", count[x]);
prints the count of number of appearances of the last letter.
taylor => 1 (r occurs 1 time)
apple => 1 (e once)
erroneousnesses => 5 (s count)
you need to loop over count array adding all counts > 1
I have a txt file that looks like the following:
1:0
2:0
3:1
4:0
...
99:1
100:1
I would like to store the 1s and 0s inside an array (slot[]), (regardless of what's on the left side of the ':'s), but I can't figure out how. Here's a snippet of my code for that:
while((ch=fgetc(fptr)) != EOF)
{
if(ch == ':')
{
slot[j] = fgetc(fptr); //saves the character right after ":"into slot[j]?
j++;
}
}
I know it's more complicated than this because it doesn't work. I've searched for a long time but can't find it, maybe because I didn't search for the correct terms.
How can I fix this?
Thanks in advance.
It seems pretty straight forward with some minor changes, since your specs state that there is always 1 digit on the right and is always 0 or 1, something like this should do it:
if (fptr != NULL)
{
int ch;
int j = 0;
while ((ch = fgetc(fptr)) != EOF)
{
if (ch == ':')
{
if ((ch = fgetc(fptr)) != EOF) // get digit after :
{
slot[j++] = ch - '0'; // for int array *
//slot[j++] = ch; // for char array
}
else
{
break;
}
}
}
}
Or, for a more robust method using fgets:
if (fptr != NULL)
{
char temp[100]; // must be large enough to hold the line
char *ch;
int j = 0;
while (fgets(temp, sizeof temp, fptr)) // read whole line
{
ch = strchr(temp, ':'); // find :
if (ch != NULL && (ch[1] == '1' || ch[1] == '0'))
{
// add next digit to slot[] if it's 1 or 0
slot[j++] = ch[1] - '0'; // or remove - '0' for char slot[]
}
}
}
Requires string.h header for strchr.
* Check this post if you want to know more about character to digit conversion:
Why is there a need to add a '0' to indexes in order to access array values?
The reason it doesn't do what you expect is because you are reading characters and expecting them to be numbers. A character in C has an integer value. The mapping is called ASCII (have an internet search for "ASCII table"). The uppercase alphabet starts at 65, the lower case alphabet starts at 97, and the numeric digits start at 48. So, if '0' is 48 and '1' is 49 you can change '0' and '1' to 0 and 1 respectively by subtracting 48 from each:
slot[j] = fgetc(fptr) - 48;
And that works but later you will forget what 48 means and have to look at an ASCII table again so you should use characters:
slot[j] = fgetc(fptr) - '0';
Which does the same exact thing but makes it obvious why you are subtracting a value.
You can use the same trick to convert upper case to lower case:
if (ch >= 'A' && ch <= 'Z') ch += 32;
Or lower case to upper case:
if (ch >= 'a' && ch <= 'z') ch -= 32;
But of course, there are library functions called tolower() and toupper() which are much more expressive which is why nobody does it that way.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
As a part of an assignment I've got, I need to get from a user a digit only using the <stdio.h> library.
do {
scanf("%d",&num);
} while (num>9 || num<0);
But the program will get from the user also chars and other things.
Any advice?
One way of solving this is getting the ASCII value of the scanned "digit" and making sure it lies between ASCII values 0X30 and 0X39 (or 48 and 57).
Seeing your logic, you seem to be interested in numbers greater than 9 (multiple digit numbers) and numbers less than 0 (signed numbers/integers).
I suggest instead of using scanf better use something like getchar which will return one character at a time.
A simple way to scan multiple digit numbers using getchar can be:
int getNumber()
{
int sign = 1;
int i = 0;
int ch;
ch = getchar();
if((ch == '-') || (ch == '+')) //check sign
{
if(ch == '-') sign = -1;
}
else
{
if (ch > '9' || ch < '0')
return NULL; // Your requirement - it's a non number
i *= 10;
i += ch - '0';
}
while ((ch = getchar()) != '\n') //get remaining chars
{
if (ch > '9' || ch < '0')
return NULL; // Your requirement - it's a non number
i *= 10;
i += ch - '0';
}
i *= sign; //change sign
return i;
}
You can call this function in place of scanf.
You can use getchar() to read a single character from stdin and then compare it to the ASCII values for 0 and 9 (your upper and lower bounds for a single character). The digit as an integer is equal to the character code minus the character code for 0.
#include <stdio.h>
int main(void) {
char c;
while((c = getchar()) >= '0' && c <= '9')
printf("Digit is: %d\n", c - '0');
return 0;
}
This is my first post on stack overflow :)
I didn't find relevant post to my issue despite numerous posts on "counting words".
I started C 2 weeks ago. I have to return the number of words in a string, this is part of a larger exercise I m working on at the moment. I can't figure out why it doesn't work and I am kindly asking for some tips here.
ft_strlen(char *str) //counting nb of char in the string
{
int size;
size = 0;
while (str[size])
size++;
return (size);
}
int ft_word_count(char *str)
{
int i;
int size;
int count_word;
i = 0;
size = ft_strlen(str);
count_word = 0;
while (str[i] < size - 1) //counting nb of words in the string, I added "-1" to size to get rid of the '\0'
{
if (i <= 32 || i > 126 ) //defining what will make a word
count_word++;
i++;
}
return (count_word);
}
int main(void)
{
char str[]="Meine Frau liebt grosse Pferde";
ft_strlen(str);
printf("%d", ft_word_count(str));
return (0);
}
it returns 0 instead of 5, strangely, don't figure out why.
If I just use my strlen, it returns "30", as expected. So something is wrong with ft_word_count
Compiled with gcc.
Syntax is not concise but is part of the norm asked by my school.
thanks for your input
Charles
you should ignore multiple spaces for counting correct
i=0;
count_word=0;
while(str[i]>0)
{
if((str[i]!= ' '))
{
if(!toggle && str[i]!= ' ')
count_word++;
toggle=1;
}
else
toggle=0;
i++;
}
I believe that you meant to use logic more like this:
if(str[i] <= 32 || str[i] > 126) count_word++;
In the code that you posted, you are looking at the value of your index, not the character value in the string.
Even so, this is not why you are receiving "0" as a result. The cause of this is your while condition. You are checking to see if the numeric ASCII value within the string is greater than the length of the string... which I can assure you, it is. Therefore, you also want to change your white to be:
while(i < size - 1)
Personally, I would likely have checked for \n, space and \t instead, but to each his own!
The problem is these lines
while (str[i] < size - 1) // Here you compare the individual chars and
// the length of the string. That makes
// no sense
{
if (i <= 32 || i > 126 ) // Here you compare the index i and some
// fixed numbers. That makes no sense
count_word++;
i++;
}
It seems you have swapped the two, i.e. you use str[i] when you should use i and you use i when you should use str[i]
So if you change your code to:
while (i < size - 1)
{
if (str[i] <= 32 || str[i] > 126 )
count_word++;
i++;
}
You'll see that things start to make more sense. That code will print 4. That is still wrong but now you have some code that you can continue with.
A simple approach could be:
while (i < size - 1)
{
if (str[i] == ' ')
count_word++;
i++;
}
count_word++;
That code will print 5. However, the code is too simple as it count double spaces as words.
In other words - you need to add more code to handle such case but I guess that is part of the learning process. Good luck.
Error Part
while (str[i] < size - 1)
Here its checking with the ascii value at that place of string which will always be false and hence loop is not running.
Correct Way
while (i < size - 1)
{
if (str[i] == ' ')
count_word++;
i++;
}
count_word++;
There are multiple problems in your code:
while (str[i] < size - 1) is incorrect as you are comparing the value f the character to the size of the string instead of the index: it should be while (i < size).
if (i <= 32 || i > 126 ) is incorrect: it is not a proper way to check for word separators as non ASCII characters will not be considered part of the word and the encoding might not be ASCII anyway. You should instead use isspace() from <ctype.h>.
Furthermore, counting the spaces is not a way to count the words. You should instead count the number of transitions from space to non-space.
Here is a simpler version:
#include <ctype.h>
#include <stdio.h>
int ft_word_count(const char *str) {
unsigned char c, last = ' ';
int count = 0;
for (int i = 0; (c = str[i]) != '\0'; i++) {
if (!isspace(c) && isspace(last))
count++;
last = c;
}
return count;
}
int main(void) {
char str[] = "Meine Frau liebt grosse Pferde";
printf("%d\n", ft_word_count(str));
return 0;
}
all.
I've written a program as a solution to Kernighan & Ritchie's exercise 2-3, and its behaviour during testing is (IMHO) wildly unintuitive.
The problem spec says to write a program that converts hex values to their decimal equivalent. The code I've written works fine for smaller hex values, but for larger hex values things get a little... odd. For example, if I input 0x1234 the decimal value 4660 pops out on the other end, which happens to be the correct output (the code also works for letters, i.e. 0x1FC -> 508). If, on the other hand, I were to input a large hex value, say as a specific example 0x123456789ABCDEF, I should get 81985529216486895, though instead I get 81985529216486896 (off by one digit!).
The error in conversion is inconsistent, sometimes with the decimal value being too high and other times too low. Generally, much larger hex values result in more incorrect place values in the decimal output.
Here's my program in its entirety:
/*Kernighan & Ritchie's Exercise 2-3
Write a function 'htoi' which converts a string of hexadecimal digits (including an
optional 0x or 0X) into its equivalent integer value.
*/
#include <stdio.h>
#define MAXLINE 1000 //defines maximum size of a hex input
//FUNCTION DEFINITIONS
signed int htoi(char c); //converts a single hex digit to its decimal value
//BEGIN PROGRAM////////////////////////////////////////////////////////////
main()
{
int i = 0; //counts the length of 'hex' at input
char c; //character buffer
char hex[MAXLINE]; //string from input
int len = 0; //the final value of 'i'
signed int val; //the decimal value of a character stored in 'hex'
double n = 0; //the decimal value of 'hex'
while((c = getchar()) != '\n') //store a string of characters in 'hex'
{
hex[i] = c;
++i;
}
len = i;
hex[i] = '\0'; //turn 'hex' into a string
if((hex[0] == '0') && ((hex[1] == 'x') || (hex[1] == 'X'))) //ignore leading '0x'
{
for(i = 2; i < len; ++i)
{
val = htoi(hex[i]); //call 'htoi'
if(val == -1 ) //test for a non-hex character
{
break;
}
n = 16.0 * n + (double)val; //calculate decimal value of hex from hex[0]->hex[i]
}
}
else
{
for(i = 0; i < len; ++i)
{
val = htoi(hex[i]); //call 'htoi'
if(val == -1) //test for non-hex character
{
break;
}
n = 16.0 * n + (double)val; //calc decimal value of hex for hex[0]->hex[i]
}
}
if(val == -1)
{
printf("\n!!THE STRING FROM INPUT WAS NOT A HEX VALUE!!\n");
}
else
{
printf("\n%s converts to %.0f\n", hex, n);
}
return 0;
}
//FUNCTION DEFINITIONS OUTSIDE OF MAIN()///////////////////////////////////
signed int htoi(char c)
{
signed int val = -1;
if(c >= '0' && c <= '9')
val = c - '0';
else if(c == 'a' || c == 'A')
val = 10;
else if(c == 'b' || c == 'B')
val = 11;
else if(c == 'c' || c == 'C')
val = 12;
else if(c == 'd' || c == 'D')
val = 13;
else if(c == 'e' || c == 'E')
val = 14;
else if(c == 'f' || c == 'F')
val = 15;
else
{
;//'c' was a non-hex character, do nothing and return -1
}
return val;
}
pastebin: http://pastebin.com/LJFfwSN5
Any ideas on what is going on here?
You are probably exceeding the precision with which double can store integers.
My suggestion would be to change your code to use unsigned long long for the result; and also add in a check for overflow here, e.g.:
unsigned long long n = 0;
// ...
if ( n * 16 + val < n )
{
fprintf(stderr, "Number too big.\n");
exit(EXIT_FAILURE);
}
n = n * 16 + val;
My less-than check works because when unsigned integer types overflow they wrap around to zero.
If you want to add more precision than unsigned long long then you will have to get into more advanced techniques (probably beyond the scope of Ch. 2 of K&R but once you've finished the book you could revisit).
NB. You also need to #include <stdlib.h> if you take my suggestion of exit; and don't forget to change %.0f to %llu in your final printf. Also, a safer way to get the input (which K&R covers) is:
int c;
while((c = getchar()) != '\n' && c != EOF)
The first time I ran the code on ideone I got segfault, because I didn't put a newline on the end of the stdin so this loop kept on shoving EOF into hex until it buffer overflowed.
This is a classic example of floating point inaccuracy.
Unlike most of the examples of floating point errors you'll see, this is clearly not about non-binary fractions or very small numbers; in this case, the floating point representation is approximating very big numbers, with the accuracy decreasing the higher you go. The principle is the same as writing "1.6e10" to mean "approximately 16000000000" (I think I counted the zeros right there!), when the actual number might be 16000000001.
You actually run out of accuracy sooner than with an integer of the same size because only part of the width of a floating point variable can be used to represent a whole number.