Could anyone help me figure out how to extract 10/3 from a string, perform the math of 10/3 as a float/double, and store the result? I've tried modifying an older code that I have but I couldn't get it to work. This is that code:
#include<stdio.h>
#include<string.h>
#define SLASH "\\."
int main(void){
char path[100];
printf("Enter file path: \n");
fgets(path, sizeof(path), stdin);
path[strlen(path) - 1] = '\0';
char *token = strtok(path, SLASH);
while(token != NULL){
printf("%s\n", token);
/*Rather than printf the result
I've tried saving the result to
a variable but I could only get
10 to save*/
token = strtok(NULL, SLASH);
}
return 0;
}
I will then be putting the solution into this portion of a larger program:
} else if(j == 6){
arr3[j][(strlen(arr3[j])) - 1] = NULL;
sprintf(temp_arr, "%.18lf", atof(arr3[j]));
strcat(arr3[j], temp_arr);
strcat(arr3[j], new_line);
} else if(j == 7){
I read the following in from a .csv file:
input from file:
The output that I need to obtain is:
Correct output:
Could anyone give me some ideas on how to do this? I've tried to do a for loop instead of a while loop in hopes to save 10 to an array[0] and 3 to an array[1 ], but I would only get array[0] = 10 and array[1 ] = 0. Other times I would just get random junk instead of zero. Using this token approach seemed so straight-forward before but I can't convert for this task. It doesn't seem like this should be so hard for me but I'm stuck. Thanks in advance for any help that anyone can provide.
Edit:
I tweaked the first code to save each separately:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define SLASH "\\."
int main(void){
char path[100];
printf("Enter file path: \n");
fgets(path, sizeof(path), stdin);
path[strlen(path) - 1] = '\0';
char *token = strtok(path, SLASH);
while(token != NULL){
int i = 0;
char temp[100];
strcpy(temp, token);
printf("%s\n", token);
printf("temp = %s\n", temp);
token = strtok(NULL, SLASH);
i++;
}
return 0;
}
From there, I'm trying to implement that into the program that I'm actually working on.
char temp_arr[17];
} else if(j == 6){
arr3[j][(strlen(arr3[j])) - 1] = '\0';
strcpy(temp_arr, arr3[j]);
char *token = strtok(arr3[j], SLASH);
int m = 0;
while(token != NULL){
strcpy(temp_arr2, token);
printf("temp = %s\n", temp_arr2);
token = strtok(NULL, SLASH);
m++;
}
sprintf(temp_arr, "%.18lf", atof(arr3[j]));
strcat(arr3[j], temp_arr);
strcat(arr3[j], new_line);
But I'm getting 10/3 instead of 10 and 3 separately.
There are a number of ways to approach this problem. One of the simplest is to parse the string using the capabilities of strtol which will parse a string for a numeric value, convert the value to a long, and set its endptr parameter to point to one character after the last digit used in the conversion.
(which will be '/' in your case, but you should still check for any intervening spaces between the end of the number and your operator)
You can then start scanning forward from endptr until you locate '/' (or any non-numeric character to use for the operator). Save the character, and advance your pointer by one and call strtol again to convert your final number to long.
Putting the pieces together, you can do something like the following:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define BASE 10
#define EXPR 64
int main (void) {
long a, b;
char op,
expr[EXPR] = "",
*p = expr,
*ep;
printf ("enter expression: ");
if (!fgets (expr, EXPR, stdin)) {
fprintf (stderr, "error: user canceled input.\n");
return 1;
}
a = strtol (p, &ep, BASE); /* convert a to long */
if (p == ep) { /* no digits converted */
fprintf (stderr, "error: strtol - a, no digits found.\n");
return 1;
}
p = ep; /* set p to end-pointer */
while (*p && isspace (*p)) p++; /* skip any intervening spaces */
op = *p++; /* set operator char */
b = strtol (p, &ep, BASE); /* convert b to long */
if (p == ep) { /* no digits converted */
fprintf (stderr, "error: strtol - b, no digits found.\n");
return 1;
}
printf ("%ld %c %ld = ", a, op, b); /* output expression */
switch (op) { /* handle +, -, *, / */
case '+': printf ("%ld\n", a + b); break;
case '-': printf ("%ld\n", a - b); break;
case '*': printf ("%ld\n", a * b); break;
case '/': printf ("%f\n", (double)(a) / b); break;
default : printf ("(error - invalid operator)\n"); break;
}
return 0;
}
(note: you should also check errno following each call to strtol to insure there were no errors, overflow/underflow, etc.. in the conversion. That is left to you)
Example Use/Output
$ ./bin/aexprb
enter expression: 10/3
10 / 3 = 3.333333
$ ./bin/aexprb
enter expression: 10 / 3
10 / 3 = 3.333333
$ ./bin/aexprb
enter expression: 10 + 3
10 + 3 = 13
Look things over and let me know if you have further questions.
Related
I need to make a small calculator for school, using the following template: "operation(operator1, operator2)". E.G.: "Add(1, 2)" will return 3, "Multiply(2, 5)" will return 10. I know I can use a strtok to retrieve the operation, but I'm not sure how to retrieve the operators. Currently I have the following:
#include <stdio.h>
int main()
{
char Math_Input[32]; //This is where I will store the input in the following template: operation("operator1, operator2")
float Operator_1, Operator_2;
printf("What calculation do you wish to do?: ");
fgets(Math_Input,20,stdin); //Here I retrieve the entire line and I'll store it in Math_Operation, next step is to retrieve the operation, operator1 and operator2
char * Math_Operation = strtok(Math_Input, "(");
printf("%s\n", Math_Operation);
}
Update:
After a bit of code given which is using sscanf() I revised my code to the following:
#include <stdio.h>
int main()
{
char Math_Input[32]; //This is where I will store the input in the following template: operation("operator1, operator2")
char Math_operation[16];
float Operator_1, Operator_2;
printf("What calculation do you wish to do?: ");
fgets(Math_Input,20,stdin); //Here I retrieve the entire line and I'll store it in Math_Input, next step is to retrieve the operation, operator1 and operator2
if (3 != sscanf(Math_Input, "%15s (%f ,%f )", Math_operation, &Operator_1, &Operator_2)) {
fprintf(stderr, "Incorrect line >%s<\n", Math_Input);
printf("Operation: %s \n", Math_operation);
printf("Operator1: %d \n", Operator_1);
printf("Operator2: %d \n", Operator_2);
}
else {
// Ok process the operation...
printf("Else");
printf("Operation: %s \n", Math_operation);
printf("Operator1: %d \n", Operator_1);
printf("Operator2: %d \n", Operator_2);
}
}
I used a few printf's to debug. This should work in theory right? But when I test it out like this: (so this is my console) it doesnt seem to work...
What calculation do you wish to do?: Add(1, 2)
Incorrect line >Add(1, 2)
<
Operation: Add(1,
Operator1: 0
Operator2: 0
Process returned 0 (0x0) execution time : 3.698 s
Press any key to continue.
If the input is expect to be in the format operation(value_1, value2), it looks like a correct use case for sscanf. The scanf family is said to be a poor man's parser, because it has no support for error recovery. But here you have already got your input line from fgets and only need a trivial parsing. So I would just use:
char Math_Input[32]; //This is where I will store the input in the following template: operation("operator1, operator2")
char Math_operation[16];
float Operator_1, Operator_2;
printf("What calculation do you wish to do?: ");
fgets(Math_Input,20,stdin); //Here I retrieve the entire line and I'll store it in Math_Operation, next step is to retrieve the operation, operator1 and operator2
if (3 != sscanf(Math_Input, "%15[^ (] (%f ,%f )", Math_operation, &Operator_1, &Operator_2)) {
fprintf(stderr, "Incorrect line >%s<\n", Math_input);
}
else {
// Ok process the operation...
}
...
The good news with sscanf is that it will ignore any non significative blank character.
Additional improvements: make sure that fgets could get a complete line (not more than 19 characters) else read until the end of line in you later need a loop
In my opinion, the best (and most efficient) way would be to write a simple parser, something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(void)
{
char input[32], function_name[32];
float function_args[2];
char *iterator, *bufptr, buffer[32];
/* we will use buffer to temporarily store float,
and bufptr to store tokens beginning */
printf("What calculation do you wish to do?: ");
fgets(input, 20, stdin);
/* On this step we have input, probably in format `name(val1, val2)`.
Now we are going to parse this: */
iterator = input; /* iterator will point to first character of an input */
bufptr = iterator; /* bufptr will now point to a beginning of a token */
while (*iterator != '(' && *iterator != '\0')
++iterator;
/* Now iterator points to '(', or string ended because we got
NULL-terminator, so we will check for a terminator: */
if (*iterator == '\0') { /* String ended */
fputs("Syntax error :(", stderr);
exit(1);
}
/* Copying function name to function_name variable.
We will copy amount of characters equal iterator - input,
because we added 1 to iterator, so iterator points to '(' now: */
strncpy(function_name, bufptr, iterator - bufptr);
/* Now, we are doing exacly the same thing, but now for ','.
You can surround this loops with a function: */
++iterator; /* iterator points to '(', so we will just add 1 */
bufptr = iterator;
while (*iterator != ',' && *iterator != '\0') ++iterator;
if (*iterator == '\0') { /* String ended */
fputs("Syntax error :(", stderr);
exit(1);
}
strncpy(buffer, bufptr, iterator - bufptr);
function_args[0] = strtof(buffer, NULL);
/* Now we can continue parsing, iterator now should point to a comma.
Doing same thing as upper, but now for ')' */
++iterator;
bufptr = iterator;
while (*iterator != ')' && *iterator != '\0') ++iterator;
if (*iterator == '\0') { /* String ended */
fputs("Syntax error :(", stderr);
exit(1);
}
strncpy(buffer, bufptr, iterator - bufptr);
function_args[1] = strtof(buffer, NULL);
while (*iterator != ')' && *iterator != '\0') ++iterator;
if (*iterator == '\0') { /* String ended */
fputs("Syntax error :(", stderr);
exit(1);
}
/* Printing */
printf("Function that you called: %s(%f, %f)\n",
function_name, function_args[0], function_args[1]);
/* And on this point you have all expected data, so you can call functions */
if (!strcmp(function_name, "Add")) {
Add(function_args[0], function_args[1]);
} else if (!strcmp(function_name, "Substract")) {
Substract(function_args[0], function_args[1]);
} else {
/* ... */
}
}
As you said in the comments:
the user will be typing in "Add(1,2)" or "Multiply(2,5)"
you can just do what you are doing i.e. tokenizing the string:
#include <stdio.h>
#include <string.h>
int main()
{
int data_field = 3;
char Math_Input[32];
char* Math_Operation = NULL;
// operation("operand1,operand2")
float operand_1, operand_2;
printf("What calculation do you wish to do?: ");
scanf("%31[^\n]%*c", Math_Input);
Math_Operation = strtok(Math_Input, "(");
while(data_field-- != 0)
{
printf("%s\n", Math_Operation);
if (data_field == 2)
{
Math_Operation = strtok(NULL, ",");
sscanf(Math_Operation, "%f", &operand_1);
}
if (data_field == 1)
{
Math_Operation = strtok(NULL, ")");
sscanf(Math_Operation, "%f", &operand_2);
}
}
return 0;
}
Output:
What calculation do you wish to do?: Add(2,1)
Add
2
1
P.S.: You can store operands using sscanf().
I need to get integers from a string that an user enters into the console.
For exemple:
I have this string: [1, 2, 3, 4, 5] and I would like to get all of the integers from it. I already tried multiple scanf patterns, such as scanf("%*[^\[]%d,", &a), but nothing worked. I couldn't find anything relevant on Stack Overflow either.
The main problem is that he can enters between 1 and 50 integers into his string. I have no idea about how to stock only integers (removing ',' and '[' ']' ) into an array.
Some solutions have been found for removing special chars such as [ ] or ,
But now I still need to remove SPACE between comas and integers...
EDIT : problem solved using fgets. I was using scanf to get my string, but it were stopping to SPACES.
Fond out how to do that with scanf :
while(scanf(" %d",&i))
scanf/sscanf does not support regular expressions. You should try something like:
const char my_string[] = "[1,2,3,4,5]";
int a,b,c,d,e;
sscanf(my_string, "[%d,%d,%d,%d,%d]", &a, &b, &c, &d, &e);
Example: http://ideone.com/AOaD7x
It can also be good to check the return value of scanf/sscanf:
int retval = sscanf(my_string, "[%d,%d,%d,%d,%d]", &a, &b, &c, &d, &e);
if (retval != 5)
fprintf(stderr, "could not parse all integers\n");
Reference
Edit:
In your edited question you asks how to do this if there is a variable number of integers. You can use strchr to locate the next comma in the string and continue to iterate until no more comma is found. This assumes that the string ends with ].
const char my_string[] = "[1,2,3,4,5]";
/* start at first integer */
const char *curr = &my_string[1];
while (curr != NULL) {
/* scan and print the integer at curr */
int tmp;
sscanf(curr, "%d", &tmp);
printf("%d\n", tmp);
/* find next comma */
curr = strchr(curr, ',');
/* if a comma was found, go to next integer */
if (curr)
/* warning: this assumes that the string ends with ']' */
curr += 1;
}
Example: http://ideone.com/RZkjWN
Try this piece of code, by using strtok you can separate out all type of unwanted characters in your string. Add all your unwanted set of character to this s array and let strtok do the work.
char str[]="[1,2,3,4,5]";
const char s[4] = "[],"; // All unwanted characters to be filtered out
char *token;
token = strtok(str, s);
while( token != NULL )
{
printf( "%d\n", atoi(token));
token = strtok(NULL, s);
}
Since you have it in the integer format, you could store it in an array and go further with it.
Output :
1
2
3
4
5
Using scanf() for parsing strings is not recommended.
Similarly to others answers, you can use strtok to parse the numbers between "[],", and convert the found numbers using strtol. It would be dangerous to use something like atoi() for integer conversion, as their is no error checking with it. Some more error checking with strtol() can be found in the man page.
Here is some sample(can be improved) code which does this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXNUM 50
#define BASE 10
int main(void) {
char string[] = "[1,2,3,4,5]";
char *number, *endptr;
const char *delim = "[],";
int numbers[MAXNUM], current;
size_t i, count = 0;
number = strtok(string, delim);
while (number != NULL) {
current = strtol(number, &endptr, BASE);
/* checking if valid digit found */
/* more error checking can be added */
if (endptr != number) {
numbers[count++] = current;
}
number = strtok(NULL, delim);
}
for (i = 0; i < count; i++) {
printf("numbers[%zu] = %d\n", i, numbers[i]);
}
return 0;
}
Sample input 1:
string[] = "[1,2,3,4,5]";
Output 1:
numbers[0] = 1
numbers[1] = 2
numbers[2] = 3
numbers[3] = 4
numbers[4] = 5
Sample input 2:
string[] = "[1,a,3,c,5]";
Output 2:
numbers[0] = 1
numbers[1] = 3
numbers[2] = 5
I made this code:
/*here is the main function*/
int x , y=0, returned_value;
int *p = &x;
while (y<5){
printf("Please Insert X value\n");
returned_value = scanf ("%d" , p);
validate_input(returned_value, p);
y++;
}
the function:
void validate_input(int returned_value, int *p){
getchar();
while (returned_value!=1){
printf("invalid input, Insert Integers Only\n");
getchar();
returned_value = scanf("%d", p);
}
}
Although it is generally working very well but when I insert for example "1f1" , it accepts the "1" and does not report any error and when insert "f1f1f" it reads it twice and ruins the second read/scan and so on (i.e. first read print out "invalid input, Insert Integers Only" and instead for waiting again to re-read first read from the user, it continues to the second read and prints out again "invalid input, Insert Integers Only" again...
It needs a final touch and I read many answers but could not find it.
If you don't want to accept 1f1 as valid input then scanf is the wrong function to use as scanf returns as soon as it finds a match.
Instead read the whole line and then check if it only contains digits. After that you can call scanf
Something like:
#include <stdio.h>
int validateLine(char* line)
{
int ret=0;
// Allow negative numbers
if (*line && *line == '-') line++;
// Check that remaining chars are digits
while (*line && *line != '\n')
{
if (!isdigit(*line)) return 0; // Illegal char found
ret = 1; // Remember that at least one legal digit was found
++line;
}
return ret;
}
int main(void) {
char line[256];
int i;
int x , y=0;
while (y<5)
{
printf("Please Insert X value\n");
if (fgets(line, sizeof(line), stdin)) // Read the whole line
{
if (validateLine(line)) // Check that the line is a valid number
{
// Now it should be safe to call scanf - it shouldn't fail
// but check the return value in any case
if (1 != sscanf(line, "%d", &x))
{
printf("should never happen");
exit(1);
}
// Legal number found - break out of the "while (y<5)" loop
break;
}
else
{
printf("Illegal input %s", line);
}
}
y++;
}
if (y<5)
printf("x=%d\n", x);
else
printf("no more retries\n");
return 0;
}
Input
1f1
f1f1
-3
Output
Please Insert X value
Illegal input 1f1
Please Insert X value
Illegal input f1f1
Please Insert X value
Illegal input
Please Insert X value
x=-3
Another approach - avoid scanf
You could let your function calculate the number and thereby bypass scanf completely. It could look like:
#include <stdio.h>
int line2Int(char* line, int* x)
{
int negative = 0;
int ret=0;
int temp = 0;
if (*line && *line == '-')
{
line++;
negative = 1;
}
else if (*line && *line == '+') // If a + is to be accepted
line++; // If a + is to be accepted
while (*line && *line != '\n')
{
if (!isdigit(*line)) return 0; // Illegal char found
ret = 1;
// Update the number
temp = 10 * temp;
temp = temp + (*line - '0');
++line;
}
if (ret)
{
if (negative) temp = -temp;
*x = temp;
}
return ret;
}
int main(void) {
char line[256];
int i;
int x , y=0;
while (y<5)
{
printf("Please Insert X value\n");
if (fgets(line, sizeof(line), stdin))
{
if (line2Int(line, &x)) break; // Legal number - break out
printf("Illegal input %s", line);
}
y++;
}
if (y<5)
printf("x=%d\n", x);
else
printf("no more retries\n");
return 0;
}
Generally speaking, it is my opinion that you are better to read everything from the input (within the range of your buffer size, of course), and then validate the input is indeed the correct format.
In your case, you are seeing errors using a string like f1f1f because you are not reading in the entire STDIN buffer. As such, when you go to call scanf(...) again, there is still data inside of STDIN, so that is read in first instead of prompting the user to enter some more input. To read all of STDIN, you should do something the following (part of code borrowed from Paxdiablo's answer here: https://stackoverflow.com/a/4023921/2694511):
#include <stdio.h>
#include <string.h>
#include <stdlib.h> // Used for strtol
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
#define NaN 3 // Not a Number (NaN)
int strIsInt(const char *ptrStr){
// Check if the string starts with a positive or negative sign
if(*ptrStr == '+' || *ptrStr == '-'){
// First character is a sign. Advance pointer position
ptrStr++;
}
// Now make sure the string (or the character after a positive/negative sign) is not null
if(*ptrStr == NULL){
return NaN;
}
while(*ptrStr != NULL){
// Check if the current character is a digit
// isdigit() returns zero for non-digit characters
if(isdigit( *ptrStr ) == 0){
// Not a digit
return NaN;
} // else, we'll increment the pointer and check the next character
ptrStr++;
}
// If we have made it this far, then we know that every character inside of the string is indeed a digit
// As such, we can go ahead and return a success response here
// (A success response, in this case, is any value other than NaN)
return 0;
}
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
// (Per Chux suggestions in the comments, the "buff[0]" condition
// has been added here.)
if (buff[0] && buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
void validate_input(int responseCode, char *prompt, char *buffer, size_t bufferSize){
while( responseCode != OK ||
strIsInt( buffer ) == NaN )
{
printf("Invalid input.\nPlease enter integers only!\n");
fflush(stdout); /* It might be unnecessary to flush here because we'll flush STDOUT in the
getLine function anyway, but it is good practice to flush STDOUT when printing
important information. */
responseCode = getLine(prompt, buffer, bufferSize); // Read entire STDIN
}
// Finally, we know that the input is an integer
}
int main(int argc, char **argv){
char *prompt = "Please Insert X value\n";
int iResponseCode;
char cInputBuffer[100];
int x, y=0;
int *p = &x;
while(y < 5){
iResponseCode = getLine(prompt, cInputBuffer, sizeof(cInputBuffer)); // Read entire STDIN buffer
validate_input(iResponseCode, prompt, cInputBuffer, sizeof(cInputBuffer));
// Once validate_input finishes running, we should have a proper integer in our input buffer!
// Now we'll just convert it from a string to an integer, and store it in the P variable, as you
// were doing in your question.
sscanf(cInputBuffer, "%d", p);
y++;
}
}
Just as a disclaimer/note: I have not written in C for a very long time now, so I do apologize in advance if there are any error in this example. I also did not have an opportunity to compile and test this code before posting because I am in a rush right now.
If you're reading an input stream that you know is a text stream, but that you are not sure only consists of integers, then read strings.
Also, once you've read a string and want to see if it is an integer, use the standard library conversion routine strtol(). By doing this, you both get a confirmation that it was an integer and you get it converted for you into a long.
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
bool convert_to_long(long *number, const char *string)
{
char *endptr;
*number = strtol(string, &endptr, 10);
/* endptr will point to the first position in the string that could
* not be converted. If this position holds the string terminator
* '\0' the conversion went well. An empty input string will also
* result in *endptr == '\0', so we have to check this too, and fail
* if this happens.
*/
if (string[0] != '\0' && *endptr == '\0')
return false; /* conversion succesful */
return true; /* problem in conversion */
}
int main(void)
{
char buffer[256];
const int max_tries = 5;
int tries = 0;
long number;
while (tries++ < max_tries) {
puts("Enter input:");
scanf("%s", buffer);
if (!convert_to_long(&number, buffer))
break; /* returns false on success */
printf("Invalid input. '%s' is not integer, %d tries left\n", buffer,
max_tries - tries);
}
if (tries > max_tries)
puts("No valid input found");
else
printf("Valid input: %ld\n", number);
return EXIT_SUCCESS;
}
ADDED NOTE: If you change the base (the last parameter to strtol()) from 10 to zero, you'll get the additional feature that your code converts hexadecimal numbers and octal numbers (strings starting with 0x and 00 respectively) into integers.
I took #4386427 idea and just added codes to cover what it missed (leading spaces and + sign), I tested it many times and it is working perfectly in all possible cases.
#include<stdio.h>
#include <ctype.h>
#include <stdlib.h>
int validate_line (char *line);
int main(){
char line[256];
int y=0;
long x;
while (y<5){
printf("Please Insert X Value\n");
if (fgets(line, sizeof(line), stdin)){//return 0 if not execute
if (validate_line(line)>0){ // check if the string contains only numbers
x =strtol(line, NULL, 10); // change the authentic string to long and assign it
printf("This is x %d" , x);
break;
}
else if (validate_line(line)==-1){printf("You Have Not Inserted Any Number!.... ");}
else {printf("Invalid Input, Insert Integers Only.... ");}
}
y++;
if (y==5){printf("NO MORE RETRIES\n\n");}
else{printf("%d Retries Left\n\n", (5-y));}
}
return 0;}
int validate_line (char *line){
int returned_value =-1;
/*first remove spaces from the entire string*/
char *p_new = line;
char *p_old = line;
while (*p_old != '\0'){// loop as long as has not reached the end of string
*p_new = *p_old; // assign the current value the *line is pointing at to p
if (*p_new != ' '){p_new++;} // check if it is not a space , if so , increment p
p_old++;// increment p_old in every loop
}
*p_new = '\0'; // add terminator
if (*line== '+' || *line== '-'){line++;} // check if the first char is (-) or (+) sign to point to next place
while (*line != '\n'){
if (!(isdigit(*line))) {return 0;} // Illegal char found , will return 0 and stop because isdigit() returns 0 if the it finds non-digit
else if (isdigit(*line)){line++; returned_value=2;}//check next place and increment returned_value for the final result and judgment next.
}
return returned_value; // it will return -1 if there is no input at all because while loop has not executed, will return >0 if successful, 0 if invalid input
}
The input text file has some numbers per line, numbers are split by space. The first two lines only got one number, and the following lines got three. What I want to do is read each line of the input and store these numbers.
This is what I've got so far:
int
main(int argc, char *argv[]) {
int n = 0;
char buff[MAX_STRING_LEN]; //MAX_STRING_LEN is defined as 64
while (fgets(buff,MAX_STRING_LEN, stdin) != NULL) {
char temp;
if (n == 0) {
sscanf(buff, "%s", &temp);
int h_num = (int)temp;
} else if (n == 1) {
sscanf(buff, "%s", &temp);
int s_num = (int)temp;
} else {
sscanf(buff, "%s", &temp);
char *token;
token = strtok(&temp, " ");
int i = 0;
int a,b,c;
while (token != NULL) {
if (i == 0) {
a = (int)token;
token = strtok(NULL, " ");
} else if (i == 1) {
b = (int)token;
token = strtok(NULL, " ");
} else {
c = (int)token;
token = strtok(NULL, " ");
}
i++;
}
}
n++;
}
return 0;
}
The print statement I used to test my code is like:
printf("%d\n",h_num);
printf("%d\n%d\n%d\n",a,b,c);
I created a text file like this:
23
34
4 76 91
but the output is not what I expected, it's the address of the pointer I think. (I'm stuck with pointer again =( )
Could someone help me to point out what the problem is? Appreciate it.
In your code, I can see,
int h_num = (int)temp;
and
int s_num = (int)temp;
No, that is not how you convert an aphanumeric string to int.
You need to use strtol() for this purpose.
Then,
sscanf(buff, "%s", &temp);
is wrong. temp is a char, you got to use %c for that.
My suggestion for a better approach:
Read a complete line from file using fgets()
tokenize the input using strtok(), using space () as delimiter, then convert the token (if not NULL) to int using strtol()
continue untill the returned token is NULL
In this case, your code will be much more generic, as don't need to bother seperately about the number of ints present in each line.
So, I got to a point where I have a string with words and punctuation marks ( a full sentence to be exact). I wanted to change one word in that sentence. The number of letters of the new word may not be the exact with the previous one. I also have a 2-d matrix with the words of the sentence changed now so that it has the new word instead of the old one. So I managed to trade all words in my original string with a * and keep the punctuation marks so that I can change the * with the words of the altered 2-d matrix and keep the punctuation marks. So my real question is how can I change the * of the string with whole words and then add the punctuation marks where needed.
Example:
Original string: HELLO PEOPLE. HELLO WORLD. HOW ARE YOU TODAY?
Word for change: WORLD --> MAN
String with '*': * *. * *.* * * *?
Result I want: HELLO PEOPLE. HELLO MAN. HOW ARE YOU TODAY?
I tried this (with text3 string with'*' and text 4 the result I want):
l1=0;sum3=0;
for (k=0;k<sum2;k++){
if (text3[k]=='*'){
strcpy(&text4[sum3],textb1[l1]);
l1++;
sum3=sum3+strlen(textb1[l1]);
}
else {
text4[sum3]=text3[k];
sum3++;
}
}
printf("%s\n",text4);
But I only manage to get the first HELLO printed.
Here is a full program, based on my "stack" idea, to demonstrate:
split then store words on spaces and punctuation;
store into a basic stack;
print out with spaces added where needed;
output new word whenever old word was in input.
The latter replaces every occurrence of old with new, as it was not specified the replacement should only occur once. Overflow handling of stack and memory cleanup omitted for clarity.
Pro
Spaces are always concatenated into one single space.
Easily adjustable for other scenarios.
Con
Spaces are always concatenated into one single space.
It only checks for alphanumerics and a basic punctuation set.
Handling of punctuation is very basic. For instance, initially I added () to punct as well, but these need further adjustments in the output routine that insert spaces. If necessary, you could, for instance, make stack a struct and add a spaceAfter member and save where the original spaces occurred.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char *stack[256];
int stack_depth = 0;
const char *punct = ".,:;!?";
int main (int argc, char **argv)
{
char *ptr, *find, *change;
int i;
if (argc != 3)
{
ptr = strrchr (argv[0], '/');
if (!ptr)
ptr = strrchr (argv[0], '\\');
if (ptr)
ptr++;
else
ptr = argv[0];
printf ("usage: %s \"original string\" \"original --> new\"\n", ptr);
return 0;
}
ptr = argv[1];
while (*ptr)
{
while (*ptr == ' ')
ptr++;
i = 0;
while (ptr[i])
{
/* do not store spaces */
if (ptr[i] == ' ')
break;
/* stop on punctuation */
if (strchr (punct, ptr[i]))
break;
i++;
}
if (i)
{
stack[stack_depth] = malloc(i+1);
if (stack[stack_depth] == NULL)
{
printf ("oh wow, out of memory\n");
return -1;
}
strncpy (stack[stack_depth], ptr, i);
stack[stack_depth][i] = 0;
stack_depth++;
ptr += i;
}
if (*ptr && strchr (punct, *ptr))
{
i = 0;
while (ptr[i] && strchr (punct, ptr[i]))
i++;
stack[stack_depth] = malloc(i+1);
if (stack[stack_depth] == NULL)
{
printf ("oh wow, out of memory\n");
return -1;
}
strncpy (stack[stack_depth], ptr, i);
stack[stack_depth][i] = 0;
stack_depth++;
ptr += i;
}
}
printf ("Original string: ");
for (i=0; i<stack_depth; i++)
{
if (i > 0 && !strchr (punct, stack[i][0]))
printf (" ");
printf ("%s", stack[i]);
}
printf ("\n");
/* fetch change words */
ptr = strstr (argv[2], " --> ");
if (!ptr)
{
printf ("bad syntax!\n");
return -1;
}
/* fetch the length of 'find' */
i = ptr-argv[2];
find = malloc (i+1);
strncpy (find, argv[2], i);
find[i] = 0;
/* fetch the length of 'change' */
/* this is the 5 characters ' --> ' after start */
ptr += 5;
i = strlen(ptr);
change = malloc (i+1);
strncpy (change, ptr, i);
change[i] = 0;
printf ("Word for change: %s --> %s\n", find, change);
printf ("Result: ");
for (i=0; i<stack_depth; i++)
{
if (i > 0 && !strchr (punct, stack[i][0]))
printf (" ");
if (strcmp (stack[i], find))
printf ("%s", stack[i]);
else
printf ("%s", change);
}
printf ("\n");
}
Test run:
replace "HELLO PEOPLE. HELLO WORLD. HOW ARE YOU TODAY?" "WORLD --> MAN"
Original string: HELLO PEOPLE. HELLO WORLD. HOW ARE YOU TODAY?
Word for change: WORLD --> MAN
Result: HELLO PEOPLE. HELLO MAN. HOW ARE YOU TODAY?
A few bugs:
l1=0;sum3=0;
for (k=0;k<sum2;k++){
if (text3[k]=='*'){
strcpy(&text4[sum3],textb1[l1]);
/*l1++; */ /* You are incrementing the wrong length I think.... */
sum3=sum3+strlen(textb1[l1]);
l1++;
}
else {
text4[sum3]=text3[k];
sum3++;
}
}
text4[sum3] = 0; /* Null terminate */
printf("%s\n",text4);