I'm trying to process input from stdin but keep running into walls.
My goal is to read a strem of numbers(0-99) and print each one in words.
My first attempt was:
int main(void) {
char *a[20] = {"zero","one","two","three","four","five","six","seven","eight",
"nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen",
"seventeen","eighteen","nineteen"};
char *b[8] = {"twenty","thirty","fourty","fifty","sixty","seventy","eighty","ninety"};
int num=0, tens=0, ones=0;
while (scanf("%d", &num)==1){
tens = num/10;
ones = num%10;
if (tens>1){
printf("%s ", b[tens-2]);
printf("%s \n", a[ones]);
}
else
printf("%s \n", a[num]);
}
printf("done");
return 0;
}
Output is correct but scanf never terminates the loop.
Second attempt:
int main(void) {
char *a[20] = {"zero","one","two","three","four","five","six","seven","eight",
"nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen",
"seventeen","eighteen","nineteen"};
char *b[8] = {"twenty","thirty","fourty","fifty","sixty","seventy","eighty","ninety"};
char line[1024], *ptr = NULL;
long num;
int tens=0, ones=0;
if(fgets(line, sizeof(line), stdin)!=NULL){
do {
num = strtol(line, &ptr, 10);
tens = num/10;
ones = num%10;
if (tens>1){
printf("%s ", b[tens-2]);
printf("%s \n", a[ones]);
}
else
printf("%s \n", a[num]);
}while (*ptr!= '\n');
}
printf("done");
return 0;
}
Here I get a compilation error and can't find the problem so I don't know if it works.
[UPDATE]: The second code runs but for an input of more then one number like
12 35 51 it prints the first number (twelve) infinitely.
Any help would be greatly appreciated.
You are so close. You just need to validate the return of strtol, and update the pointer address based on the endptr following the call to strtol. You should also check for values outside the range of your conversion as mentioned in the discussion. This is all that is needed:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(void) {
char *a[] = {"zero","one","two","three","four","five","six",
"seven","eight","nine","ten","eleven","twelve",
"thirteen","fourteen","fifteen","sixteen",
"seventeen","eighteen","nineteen"};
char *b[] = {"twenty","thirty","fourty","fifty","sixty",
"seventy","eighty","ninety"};
char line[1024] = "";
long num;
int tens=0, ones=0;
if (fgets (line, sizeof(line), stdin) != NULL) {
char *p = line, *ep = NULL;
errno = 0;
while (errno == 0) {
num = strtol (p, &ep, 10); /* convert to long */
if (p == ep) break; /* no digits, break */
p = ep; /* update p to ep */
if (num < 0 || 99 < num) { /* validate range */
fprintf (stderr, "error: %ld - out of range.\n", num);
continue;
}
tens = num/10;
ones = num%10;
if (tens > 1) {
printf ("%s ", b[tens-2]);
printf ("%s \n", a[ones]);
}
else
printf("%s \n", a[num]);
}
}
printf ("done\n");
return 0;
}
Example Use/Output
$ ./bin/n2string
12 55 61 -1 33 102 4
twelve
fifty five
sixty one
error: -1 - out of range.
thirty three
error: 102 - out of range.
four
done
Look it over and let me know if you have any questions.
The purpose of the code appears to be to print the text version of a digit that was entered. Your code works almost unchanged, I just added a library and ran it.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char *a[20] = {"zero","one","two","three","four","five","six","seven","eight",
"nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen",
"seventeen","eighteen","nineteen"};
char *b[8] = {"twenty","thirty","fourty","fifty","sixty","seventy","eighty","ninety"};
char line[1024], *ptr = NULL;
long num;
int tens=0, ones=0;
if(fgets(line, sizeof(line), stdin)!=NULL){
do {
num = strtol(line, &ptr, 10);
tens = num/10;
ones = num%10;
if (tens>1){
printf("%s ", b[tens-2]);
printf("%s \n", a[ones]);
}
else
printf("%s \n", a[num]);
}while (*ptr!= '\n');
}
printf("done");
return 0;
}
Test
19
nineteen
done
Maybe the problem was that you didn't know the purpose of the code.
Related
I made this function to get input:
void entrada_dados(Time* time, int i){
scanf("%s %d %d", time[i].nome, &time[i].gols_marcados, &time[i].gols_sofridos);
};
The input is in this form:
2
Campinense
23
12
ABC
30
13
The main is:
int main(void) {
int n = 0;
scanf("%d", &n);
for(int i = 0; i < n; i++){
entrada_dados(time, i);
}
....
My problem is when the team name have some space like to "São Paulo". I have tried some forms to solve, but no one solved my problem.
I tried:
void entrada_dados(Time* time, int i){
fscanf(stdin, "%[^\n] %d %d", time[i].nome, &time[i].gols_marcados, &time[i].gols_sofridos);
};
and:
void entrada_dados(Time* time, int i){
fgets(time[i].nome, 100, stdin);
scanf("%d", &time[i].gols_marcados);
scanf("%d", &time[i].gols_sofridos);
}
but in the first case the output have nothing, and second case the output miss some cases. Someone can help me to understand this problem?
Edit 1:
The definition of .name is:
typedef struct Time{
char nome[100];
int gols_marcados;
int gols_sofridos;
} Time;
Edit 2:
Solution:
One way to solve it:
Try two fscanfs fscanf(stdin, " %[^\n]", time[i].nome);
fscanf(stdin, "%d %d", &time[i].gols_marcados, &time[i].gols_sofridos);
Thank you guys.
Because you have to handle strings with spaces, it's better to use fgets for those.
But mixing fgets and scanf doesn't work too well. We can replace scanf with fgets followed by sscanf.
To decode numbers, we can use strtol or sscanf
We take advantage of the fact that each element/member of Time appears on a separate line in the input file, so we can do fgets for every line. This simplifies the code and makes error checking easier.
Here is the refactored code. It is annotated.
I didn't do this, but, if these sequences are done a lot, we can combine some of these sequences in helper functions to reduce some code replication (e.g. a function that combines the fgets followed by the sscanf)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Time {
char nome[100];
int gols_marcados;
int gols_sofridos;
} Time;
// RETURNS: 1=valid, 0=syntax error
int
entrada_dados(Time *timelist, int i)
{
char buf[100];
char *cp;
Time *tim = &timelist[i];
int valid = 0;
do {
// get name
if (fgets(tim->nome,sizeof(tim->nome),stdin) == NULL)
break;
// strip newline
tim->nome[strcspn(tim->nome,"\n")] = 0;
// get number using strtol
if (fgets(buf,sizeof(buf),stdin) == NULL)
break;
tim->gols_marcados = strtol(buf,&cp,10);
if (*cp != '\n')
break;
// get number using sscanf
if (fgets(buf,sizeof(buf),stdin) == NULL)
break;
if (sscanf(buf,"%d",&tim->gols_sofridos) != 1)
break;
// all input is okay
valid = 1;
} while (0);
return valid;
};
int
main(void)
{
int n = 0;
#if 0
scanf("%d", &n);
#else
char buf[100];
if (fgets(buf,sizeof(buf),stdin) == NULL)
exit(1);
sscanf(buf,"%d",&n);
#endif
// allocate sufficient space
Time *timelist = malloc(sizeof(*timelist) * n);
// read in data
int valid = 0;
for (int i = 0; i < n; i++) {
valid = entrada_dados(timelist, i);
if (! valid)
break;
}
// show the data
if (valid) {
for (int i = 0; i < n; i++) {
Time *tim = &timelist[i];
printf("nome='%s' gols_marcados=%d gols_sofridos=%d\n",
tim->nome,tim->gols_marcados,tim->gols_sofridos);
}
}
return 0;
}
Here is the program input:
3
Campinense
23
12
ABC
30
13
São Paulo
17
82
Here is the program output:
nome='Campinense' gols_marcados=23 gols_sofridos=12
nome='ABC' gols_marcados=30 gols_sofridos=13
nome='São Paulo' gols_marcados=17 gols_sofridos=82
I assumed using strtok would be best because of the formatting of the input.
But I've run into a few problems when trying to detect errors:
an example of a line the program would read:
.data 123,456,89
.data 12, 34, 53 , 64
these are all ok.
My problem is when the input is incorrect, for example:
.data 200 4000 // no comma speration
.data 1, ,3 // ,3 should be an error
.data 4, // the extra , should be an error
.data 12.2 // the .2 should be an error
and so on
My code (SIZE is for buffer size = 30, valid_num goes through the token to see if all the chars are numbers), the idea was to first check the validity of the tokens and add them to a buffer, if all numbers are valid, add the numbers to my data base:
while((sptr = strtok(NULL, ", \t\n")) != NULL){ //this is after reading using strtok before.
if(i < SIZE && valid_num(sptr)){ //buffer is not full and the token contains only numbers
temp_num = atoi(sptr);
if(temp_num >= MIN_VAL && temp_num <= MAX_VAL){ //number is within the required size
buffer[i] = temp_num; /*fill buffer*/
i++;
}
else{
fprintf(stderr, "(%d) Error: %d is out of bounds. Valid numbers are between %d and %d\n", line_count, temp_num, MIN_VAL, MAX_VAL);
}
}
else{
fprintf(stderr, "(%d) Error: %s is not a valid number\n",line_count, sptr);
}
tok_count++;
}
if(i == tok_count){ //if all tokens were read correctly, add the data to database.
DC += add_data(buffer, tok_count, DC, data_Table);
}
else{
if(sptr != NULL){
fprintf(stderr, "(%d) Error: %s is not a digit, .data can only be used for integers\n", line_count, sptr);
}
}
Should I try to do the same but with sscanf, even though the length of the input is unknown?
How can I enforce a certain pattern? number - comma - number ...
Perhaps using a few different strtok inside the loop?
There are many ways to parse the line.
OP's temp_num = atoi(sptr); does not detect overflow as 1) overflow with atoi() is undefined and 2) there is no error return value.
I believe the below will cope with all hostile input. It does not use strtok(), but strtol() to find non-numeric input.
Making use of helper functions provides clarity of each step.
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
void consume_whitespace(char **input) {
while (isspace((unsigned char ) **input))
(*input)++;
}
int parse_int(char **input, int *dest) {
char *endptr;
errno = 0;
long y = strtol(*input, &endptr, 10);
if (*input == endptr) return -1; // no conversion
if (errno) return -1; // overflow
#if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
if (y < INT_MIN || y > INT_MAX) return -1; // overflow
#endif
*input = endptr;
*dest = (int) y;
return 0;
}
int parse_data_line(char *input, const char *prefix, int *dest, int n) {
size_t prefix_length = strlen(prefix);
if (memcmp(input, prefix, prefix_length)) return -1;
input += prefix_length;
int i;
for (i = 0; i < n; i++) {
consume_whitespace(&input);
if (*input == '\0') break;
if (i > 0 && *input++ != ',') return -1;
if (parse_int(&input, &dest[i])) return -1;
}
consume_whitespace(&input);
if (*input) return -1; // extra text
return i;
}
Example usage
#define SIZE 30
int main() {
int numbers[SIZE];
char *input = foo();
int count = parse_data_line(input, ".data", numbers, SIZE);
if (count < 0) puts("Fail");
else bar(numbers, count);
}
Ok so I need to input a string like this
IP_1/MASK IP_2 NUM [NET_1 NET_2 NET3 ... NET_NUM]
for example :
192.168.25.87/24 192.168.26.1 3 192.168.0.0/16 192.0.26.0/16 192.168.26.0/24
And then to split this string into multiple variables ( IP_1, MASK etc).
I followed on internet a guide how to split it and I did it like this:
int main()
{
char* IP_1[256],IP_2[256],NET[256][256],character[256];
int MASCA,NUM,i=1,j;
char *p;
gets(character);
p=strtok(character,"/ ");
while(p!=NULL)
{
printf("%s\n",p);
p=strtok(NULL,"/ ");
}
So, doing this I split the array into multiple elements, but how can I save these elements into IP_1, MASK IP_2, NUM NET_1 etc ... ?
There are many way.
For example, do as follows.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void){
char IP_1[256], IP_2[256], NET[256][256], line[256], rest[256];
int MASK, NUM, i;
char *p;
fgets(line, sizeof line, stdin);//gets has already been abolished.
//Since the first three elements are fixed, use sscanf
if(3 > sscanf(line, "%s %s %d %255[^\n]%*c", IP_1, IP_2, &NUM, rest)){
printf("invalid input\n");
return -1;
}
if(NULL==(p = strchr(IP_1, '/'))){
printf("invalid input\n");
return -1;
}
*p = 0;// Replace '/' with '\0'
MASK = atoi(p + 1);// convert next '/' to int
for(p=strtok(rest, " \n"), i = 0; i < NUM && p; ++i, p=strtok(NULL, " \n")){
strcpy(NET[i], p);//strtok and copy
}
//test print
printf("IP_1:%s\n", IP_1);
printf("MASK:%d\n", MASK);
printf("IP_2:%s\n", IP_2);
for(i = 0; i < NUM; ++i)
printf("NET_%d:%s\n", i + 1, NET[i]);
}
I have a string, like "101 1 13" and I need to split it to a int aux[3] --> resulting in aux[0] = 101, aux[1] = 1 and aux[2] = 13 (in this case). How can
I do that?
In the example of the code below I get op as a String and want to get the value of the INTs in there. Each int is divided in the string by a white space(" ").
Another detail: I need the code to compile with flag -std=c99, so the answer that was accepted would not work.
#include <stdio.h>
#include <stdlib.h>
//example of str = "101 1 14" (char *)
// example of output = {101, 1, 14}(int *)
int* stoi(char *str) {
// function to split str into 3 ints
}
int main() {
char op[10];
int num[3];
scanf("%s\n", op);
num = stoi(op);
printf("%d %d %d", num[0], num[1], num[2]);
return 0;
}
First you need to tokenize your input (break apart the input into distinct elements). Then you need to parse/integerize the individual tokens by converting them from strings to the desired format.
Sample Code
#include <stdio.h>
#include <string.h>
#define BUF_LEN (64)
int main(void)
{
char buf[BUF_LEN] = { 0 };
char* rest = buf;
char* token;
int i = 0;
int iArr[100] = { 0 };
if ( fgets(buf, BUF_LEN, stdin) != NULL )
{
strtok(buf, "\n"); // Remove newline from input buffer in case we want to call fgets() again.
while ( (token = strtok_r(rest, " ", &rest)) != NULL )
{
iArr[i] = strtol(token, NULL, 10);
printf("Token %d:[%d].\n", i, iArr[i]);
i++;
}
}
return 0;
}
Sample Run
1231 12312 312 1232 1312
Token 0:[1231].
Token 1:[12312].
Token 2:[312].
Token 3:[1232].
Token 4:[1312].
Try to replace your code by following code.
The new code works only if input contains only single space between integers.
Your code:
while(op[cont] != '\0') {
for(i = 0; op[cont] != ' '; i++, cont++) {
num[i] += op[cont];
}
printf("num[i] = %d\n", num[i]);
}
New code:
while(op[cont] != '\0')
{
if(op[cont] != ' ')
num[i] = num[i]*10 + (op[cont]- '0');
else
i++;
cont++;
}
See this example of how to do that:
char string [10] = "101 1 666"
int v [3], n=0, j=0;
int tam = strlen(string);
int current_Len = 0;
for(i=0; i<tam; i++){
//32 = ascii for White space
if(string[i] != 32){
n = n*10 + string[i] - '0';
current_len++;
} else if (current_len > 0){
v[j++] = n;
current_len = 0;
n=0;
}
}
if (current_len > 0){
v[j++] = n;
}
This answer is assuming you know how much integers your string contain at the time of writing your code. It also uses specific clang/gcc extension (typeof) and may not be portable. But it may be helpful to someone (I mainly wrote it because I had nothing good to do).
#include <stdio.h>
#include <string.h>
struct {int _[3];} strToInt3(const char (*pStr)[])
{
int result[3] = {0}, *pr = result;
for(register const char *p = *pStr; *p; ++p)
{
if(*p == ' ') ++pr;
else
*pr *= 10,
*pr += *p - '0';
}
return *(__typeof__(strToInt3(0)) *)result;
}
int main()
{
char op[10];
int num[3];
scanf("%10[^\n]", op),
//memcpy(num, strToInt3(op)._, sizeof(num));
//or
*(__typeof__(strToInt3(0)) *)num = strToInt3(op);
printf("%d %d %d", num[0], num[1], num[2]);
}
I've commented the copying of returned array using memcpy and added a structure assignment. Although both must be valid (not standard I guess but working in most cases) I prefer the second option (and maybe some compiler optimizers will).
Also I assume ASCII character set for chars.
I found an easier approach to the problem. I insert a scanf, that don't catch the space blanket and convert it using atoi. As it is just 3 ints it doesn't become so bad to use this simple, repetitive way of catching the values. And it work with the -std=c99 flag, that I needed to use.
scanf("%s[^ ]\n", op);
num[0] = atoi(op);
scanf("%s[^ ]\n", op);
num[1] = atoi(op);
scanf("%s[^ ]\n", op);
num[2] = atoi(op);
printf("%d\n", num[0]);
printf("%d\n", num[1]);
printf("%d\n", num[2]);
I'd appreciate any help I can get. I'm not sure I completely understand this program. I also get the following errors when I try to run it.
I was also told that on line 15 I was trying to mod a char array. What should I be doing? Thanks for taking a look.
structFinal.c: In function print_part':
structFinal.c:14: error: invalid operands to binary %
structFinal.c: In function main':
structFinal.c:36: error: syntax error before ']' token
#include <stdio.h>
#define NAME_LEN 25
typedef struct {
int number;
char name[NAME_LEN+1];
int on_hand;
} part;
void print_part(part p[], int ind) {
int i;
printf("Whole List\n");
for(i = 0; i< ind; i++)
{
if(p[ind].name % 2 == 0)
printf("Part number: %d\n", p[ind].number);
printf("Part name: %s\n", p[ind].name);
if(p[ind].on_hand < 5)
printf("Quantity on hand: %d\n", p[ind].on_hand);
}
printf("%d\n", p[ind].number);
fgets(p[ind].name,50,fp);
fscanf(fp, "%d", &p[ind].on_hand);
printf("%s\n----%d\n", p[ind].name, p[ind].on_hand);
ind++;
fscanf(fp, "%d", &p[ind].number);
a = fgetc(fp);
} print_part(p[ ] , ind);
fclose(fp);
return 0;
Edit: I just tried this on my Ubuntu machine in Netbeans and it ran. We're suppose to run this in Unix and that's were it fails. I'm lost.
Edit: This is my final file so far. I'm pretty sure this works.
#include <stdio.h>
#define NAME_LEN 25
typedef struct {
int number;
char name[NAME_LEN+1];
int on_hand;
} part;
void print_part(part p[], int ind) {
int i;
printf("Whole List\n");
for(i = 0; i< ind; i++)
{
printf("Part number: %d\n", p[i].number);
printf("Part name: %s\n", p[i].name);
printf("Quantity on hand: %d\n", p[i].on_hand);
}
}
int main() {
/* first try, input only one set and print it */
part p[50];
int ind=0;
FILE *fp;
fp = fopen("structTest.txt", "r");
fscanf(fp, "%d", &p[ind].number);
char a;
a = fgetc(fp); /* extract the return symbol out of input buffer */
while (p[ind].number != 0)
{
while (a != '\n')
{
a = fgetc(fp);
}
printf("%d\n", p[ind].number);
fgets(p[ind].name,50,fp);
fscanf(fp, "%d", &p[ind].on_hand);
printf("%s\n----%d\n", p[ind].name, p[ind].on_hand);
ind++;
fscanf(fp, "%d", &p[ind].number);
a = fgetc(fp);
}
print_part(p , ind);
fclose(fp);
return 0;
}
/*
the code is fixed so it will extact all white spaces after a part number
is typed. the getchar while loop will keep get one character to var a
until a return key is reached
*/
Here you have some character at the end. Notices this ` which doesn't belong there?
if(p[ind].name % 2 == 0)`
And this
print_part(p[ ] , ind);
should be
print_part(p , ind);
p[ind].name is a characters array, you cannot run modulu operation on it.
You can run % on numbers - integers.
What would a logical meaning be of doing module on a string? (char array)
Say you have the array contents of abcde what is abcde % 2?