I'm getting some very strange behavior out of the atoi command. I am trying to find 2 values out of a range with the format [1:2]
The string being created is done with a dynamic string allocating macro (if Sasprintf throws you)
It will be read in from a file at projects end, however.
Anyway, I seem to be parsing my string correctly, given the correct values of token and token2. I'm confused, however, why calling atoi on token2 would give me a gibberish answer. Also, I found out in the midst of this that strtok is deprecated, I just haven't bothered switching it yet, until I solve this bug.
char *token;
char *token2;
int lsb = 0;
int msb = 0;
char *str = NULL;
Sasprintf(str,"[4:0]");
token = strtok(str,"[");
if(token != NULL)
{
token = strtok(token,":");
msb = atoi(token);
printf("%d\n", msb);
token2 = strtok(NULL,"]");
puts(token2);
lsb = atoi(token2);
printf("%d\n",token2);
}
OUTPUT
4
0
19853443
I think, you need to change
printf("%d\n",token2);
to
printf("%d\n",lsb);
token2 is a char * and you cannot print that using %d. Invokes undefined behavior
That said, always check the return value of strtok() against NULL. Also, strtod() is a better alternative to atoi().
printf("%d\n",token2);
This is not how you print a string, use:
printf("%s\n",token2);
or
printf("%d\n", lsb);
to print the result of your conversion.
Related
I have a buffer that holds a string from a CSV file that I opened and read. I split the string up by using strtok() and split on the " , ". So now my string looks like this:
char buff[BUFFER_SIZE] = "1000" "CAP_SETPCAP" "CAP_NET_RAW"
I want to make comparisons now for each section of the string, but for the life of me I cannot get it to work. I want to be able to do it without hard coding anything meaning I don't want to assume how many spaces I need to move over. For example to start at CAP_SETPCAP I don't want to have to put buff+5. Anybody know a better way to handle this?
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define BUFFER_SIZE 1024
int main(int argc, char *argv[]) {
FILE *fp = fopen("csvtest.csv", "r");
char buff[BUFFER_SIZE];
fgets(buff, 1024, fp);
char *csvData = strtok(buff, ",");
while(csvData != NULL){
csvData = strtok(NULL, ",");
}
int i;
while(buff[i] != '\0'){
strcmp(buff, "CAP_NET_RAW")
printf("Match found");
i++;
}
//or I wanted to do string comparison, but I kept getting
//segmentation fault (core dumped)
char *found;
found = strstr(buff, "CAP_NET_RAW");
printf("%s\n", found);
fclose(fp);
return 0;
}
Your code has three different sections. Lets analyze them:
1. The strtok section
You get the data from the file and then you iterate on strtok:
fgets(buff, 1024, fp);
char *csvData = strtok(buff, ",");
while(csvData != NULL){
csvData = strtok(NULL, ",");
}
You seem not interested in what you found in the different positions: in fact csvData is always overwritten with the last token. And at last it is equal to NULL.
The only thing you get is having the commas in the original array buff overwritten with '\0'. Printing buff you will only see "1000", because after this substring there is the string terminator placed by strtok.
2. Searching "CAP_NET_RAW"
You now iterate on buff[i] until the string terminator. But the string terminator is after the first substring "1000"!
int i;
while(buff[i] != '\0'){
strcmp(buff, "CAP_NET_RAW")
printf("Match found");
i++;
}
Furthermore you search for CAP_NET_RAW, but even without the inner-terminators-issue, the comparison would never succeed. That's because (1) the string actually present in buff is "CAP_NET_RAW" (with double quotes); (2) that token is the last of the row, an it sitll will have the trailing '\n' (fgets doesn't remove it).
By the way: I copied the code after your edit, and now there's no check on strcmp() return value. I suppose it is a typo. Note: strcmp returns 0 if the string match.
3. The strstr attempt
Finally you look for the string using the strstr function. That's a clever idea. But as already said before, buff doesn't contain it. Well, the buffer actually do contain it, but string utilities will stop at the first '\0' they found.
char *found;
found = strstr(buff, "CAP_NET_RAW");
printf("%s\n", found);
So found will be NULL, and dereferencing a NULL pointer (that's what %s tells printf to do) will lead to a segmentation fault.
4. Conclusions
As a very simple way to find the only string you care of, I suggest to use only strstr, without using strtok before. Alternatively you can still use strtok, but saving tokens in different strings so that you can access them later.
This is my code:
char str[] ="";
scanf("%s",&str);
char * pch;
pch = strtok (str,"#");
printf ("%s\n",pch);
return 0;
I need to render an input of "1#2#3" to three integers first, second and third.
My code above tackles only the first variable and prints the first string "1" but i want to save it to an int variable.
I tried:
int first = atoi(&pch)
But 'first' get's the value 0 instead of 1. How can i parse a pointer of an array char to int?
If you know the precise layout of the input, and the exact number of ints, you can simplify this greatly:
scanf("%d#%d#%d", &a, &b, &c);
Here is a link to a demo on ideone.
The code has undefined behaviour as str is not large enough to handle any input. str can hold at most 1 char and scanf() will append a null terminator when it reads in a string. If the user enters a single character and hits return then scanf() will write beyond the bounds the array str.
To correct, decide the maximum length of string that is acceptable and prevent scanf() by reading more:
char str[1024];
if (1 == scanf("%1023s", str))
{
}
Note that atoi() produces a result of 0 for invalid input or for "0", which is not helpful. Use strtol() instead or see the answer from dasblinkenlight for a simpler solution.
You pass a char* to atoi(), not a char**. Just call it as atoi(pch)
You have declared str as char str[] ="";. This would allocate only one byte to str.
Is it working correctly. I hope I am not missing something here.
As for strtok, you need to use it in a while loop
pch = strtok (str,"#");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, "#");
}
I’m taking a course in C and we have to make a program for the classic Postfix evaluation problem. Now, I’ve already completed this problem in java, so I know that we have to use a stack to push the numbers into, then pop them when we get an operator, I think I’m fine with all of that stuff. The problem I have been having is scanning the postfix expression in C. In java it was easier because you could use charAt and you could use the parseInt command. However, I’m not aware of any similar commands in C. So could anyone explain a method to read each value from a string in the form:
4 9 * 0 - =
Where the equals is the signal of the end of the input.
Any help would be greatly appreciated and thank you in advance :)
Let's suppose you input is in an array of characters.
char input[] = "4 9 * 0 - =";
you can access individual characters by accessing each individual array element
if (input[4] == '*') /* deal with star */;
or you can use pointer arithmetic and parse from a different point in the input (remember to #include <stdio.h> for the prototype for `sscanf´)
if (sscanf(input + 2, "%d", &number) != 1) /* deal with error */;
Or, as suggested by Chris Lutz in a comment, use strtol (after the proper #include <stdlib.h>)
number = strtol(input + 2, &next, 10);
/* don't forget to check for errors! */
/* `next` now points to the character after the `long` at position 2 in the array */
C strings are arrays of chars: char[] or char*.
you can use a for loop to iterate it and get each characher by it's index:
for (int i = 0; i < strlen(yourString); i++)
{
char ch = yourString[i];
// ...
}
Also there is a function, strtok() that might be helpful here for tokenizing the string:
#include <string.h>
#define NULL (void*)0
char yourString[] = "4 9 * 0 - =";
char delimiters[] = " "; // could be " +*/-=" depending on your implementation
char *token = NULL;
token = strtok(yourString, delimiters);
while(token != NULL)
{
printf("current token is: %s\n", token);
// do what ever you want with the token
token = strtok(NULL, delimiters); // next token
}
You can also know with sscanf how many items have been read (the counter of well read data items is the result of sscanf) and what is the relative position (using the %n format specifier).
so you could also code
int pos = 0;
int endpos = 0;
int val = 0;
if (sscanf(input + pos, "%d %n", &val, &endpos) >= 1) {
// val has been read as an integer, handle it
stack[top++] = val;
pos += endpos; // skip to next token in input
}
There are many more ways of doing that. You might want to read about lexers and parsers, e.g. with flex and bison, or antlr, etc.
How can I convert a char to Int?
This is what I have done so far.
Thanks
scanf("%s", str );
printf("str: %s\n", str);
int i;
if(isdigit(*str))
i = (int) str;
else {
i = 3;
}
test case
7
str: 7
i: 1606415584
Edit: I could have sworn the post was tagged C++ at the start. I'll leave this up in case the OP is interested in C++ answers and the change to C tag was an edit.
A further option, which may be advanced given the question, is to use boost::lexical_cast as so:
scanf("%s", str );
printf("str: %s\n", str);
int i = boost::lexical_cast<int>( str );
I have used boost::lexical_cast a lot to convert between types, mostly strings and primitives when reading in user-defined properties. I find it an invaluable resource.
It's worth noting that boost::lexical_cast can throw exceptions, and these should be appropriately handled when you use the call. The link I posted at the start of this answer contains all the information you should need regarding that.
If you want to parse an integer from a string:
i = atoi(str);
You're mixing the character and string concepts here. str is a string, and str[0] (which is equivalent to *str) is a character, the first character of that string.
If you want to extract an integer from the string, try this
sscanf(str,"%d",&i);
Your
i = (int) str;
forces 4 bytes that start at the same memory address str (and for completeness sake, str is a pointer) starts to be interpreted as an integer, and that's why you get a result that's totally off.
You can convert strings to int by using sscanf
sscanf(str,"%d",&i);
http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/
i = (int) str;
is a wrong way to convert a string to number, because It copies an address to i variable (the address which str is pointing to it).
You could try this:
i = atoi(str);
or
sscanf(str,"%d",&i);
to convert your string into a number.
Note that you cannot make sure the entered string is numeric by just isdigit(*str), because it only check the first character of the string.
One possible way is this:
int isNumeric = 1;
for(int j=0;j<length(str);j++)
if( isdigit(str[j]) == false)
{
isNumeric = 0;
break;
}
if(isNumeric)
{
// Code when the string is number
// (e.g. convert the string to a number with atoi function)
}
else
{
// Code when the string is NOT number
// (e.g. show a error message)
}
I have two helper functions to break up strings in the format of decimal prices ie. "23.00", "2.30"
Consider this:
char price[4] = "2.20";
unsigned getDollars(char *price)
{
return atoi(strtok(price, "."));
}
unsigned getCents(char *price)
{
strtok(price, ".");
return atoi(strtok(NULL, "."));
}
Now when I run the below I get a segmentation fault:
printf("%u\n", getDollars(string));
printf("%u\n", getCents(string));
However when I run them seperately without one following the other, they work fine. What am I missing here? Do I have to do some sort of resetting of strtok??
My solution:
With the knowledge about strtok I gained from the answer I chose below, I changed the implementation of the helper functions so that they copy the passed in string first, thus shielding the original string and preventing this problem:
#define MAX_PRICE_LEN 5 /* Assumes no prices goes over 99.99 */
unsigned getDollars(char *price)
{
/* Copy the string to prevent strtok from changing the original */
char copy[MAX_PRICE_LEN];
char tok[MAX_PRICE_LEN];
/* Create a copy of the original string */
strcpy(copy, price);
strcpy(tok, strtok(copy, "."));
/* Return 0 if format was wrong */
if(tok == NULL) return 0;
else return atoi(tok);
}
unsigned getCents(char *price)
{
char copy[MAX_PRICE_LEN];
char tok[MAX_PRICE_LEN];
strcpy(copy, price);
/* Skip this first part of the price */
strtok(copy, ".");
strcpy(tok, strtok(NULL, "."));
/* Return 0 if format was wrong */
if(tok == NULL) return 0;
else return atoi(tok);
}
Because strtok() modifies the input string, you run into problems when it fails to find the delimiter in the getCents() function after you call getDollars().
Note that strtok() returns a null pointer when it fails to find the delimiter. Your code does not check that strtok() found what it was looking for - which is always risky.
Your update to the question demonstrates that you have learned about at least some of the perils (evils?) of strtok(). However, I would suggest that a better solution would use just strchr().
First, we can observe that atoi() will stop converting at the '.' anyway, so we can simplify
getDollars() to:
unsigned getDollars(const char *price)
{
return(atoi(price));
}
We can use strchr() - which does not modify the string - to find the '.' and then process the text after it:
unsigned getCents(const char *price)
{
const char *dot = strchr(price, '.');
return((dot == 0) ? 0 : atoi(dot+1));
}
Quite a lot simpler, I think.
One more gotcha: suppose the string is 26.6; you are going to have to work harder than the revised getCents() just above does to get that to return 60 instead of 6. Also, given 26.650, it will return 650, not 65.
This:
char price[4] = "2.20";
leaves out the nul terminator on price. I think you want this:
char price[5] = "2.20";
or better:
char price[] = "2.20";
So, you will run off the end of the buffer the second time you try to get a token out of price. You're just getting lucky that getCents() doesn't segfault every time you run it.
And you should almost always make a copy of a string before using strtok on it (to avoid the problem that Jonathan Leffler pointed out).