I have the following input:
我有以下输入:
((1828,299),(2729,2553),(2797,2929),(2200,1383),(2894,876))
and following struct:
以及结构:
struct x{
int a;
int b;
}
How can I read the input with scanf() to create an array of my structs?
如何使用scanf()读取输入以创建我的结构数组?
I have tried
我试过了
scanf("%[^, ()],%d", &arr);
if (i % 2 == 0){
arr[i].x = scanf("%d");
}else
arr[i].y = scanf("%d");
But when I tried to print these values out I got some strange characters
但是当我试图打印这些值时,我得到了一些奇怪的字符
3 个解决方案
#1
1
#include <stdio.h>
#include <stdlib.h>
struct x{
int a;
int b;
};
int count(const char *s){
if(s == NULL || *s != '(')
return 0;//bad
int n, a, b, count = 0;
for(;;){
n = -1;
if(2!=sscanf(++s, "(%d,%d)%n", &a, &b, &n) || n < 0){
return 0;
} else {
s += n;
++count;
if(*s == ',')
continue;
else if(*s == ')')
return count;
else
return 0;
}
}
}
void set(struct x *a, const char *s){
int n, c = 0;
while(2==sscanf(++s, "(%d,%d)%n", &a[c].a, &a[c].b, &n)){
s += n;
++c;
}
}
int main(void) {
char *input = "((1828,299),(2729,2553),(2797,2929),(2200,1383),(2894,876))";
int i, n = count(input);
if(n == 0){
printf("invalid format!\n");
exit(EXIT_FAILURE);
}
struct x arr[n];
set(arr, input);
for(i = 0; i < n; ++i){
printf("(%4d, %4d)\n", arr[i].a, arr[i].b);
}
return 0;;
}
#2
3
Incorrect use of scanf()
scanf()的使用不正确
-
scanf("%[^, ()],%d", ...)
expects to scan and form a string ("%[^, ()]"
) and anint
("%d"
). Code only provided for a place to save theint
.scanf(“%[^,()],%d”,...)期望扫描并形成一个字符串(“%[^,()]”)和一个int(“%d”)。代码仅提供用于保存int的位置。
-
Code did not check the return value form
scanf()
, so code if not aware of any scanning issues.代码没有检查scanf()的返回值,所以代码如果不知道任何扫描问题。
When data is a line, recommend to use fgets()
, then parse it. Could use strtok() strtol() sscanf()
. Various pros/cons to each. Example:
当数据是一行时,建议使用fgets(),然后解析它。可以使用strtok()strtol()sscanf()。每个人的各种利弊。例:
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#define MAXN (5)
// maximum size needed to print and `int`
#define INTSIZE (sizeof (int )* CHAR_BIT / 3 + 3)
// Expect buffer size needed
#define EXPECTEDSIZE (1+(2*INTSIZE + 4) + 3)
void fooo() {
int i;
struct x {
int a;
int b;
} xx[MAXN];
char buf[EXPECTEDSIZE * 2]; // I favor 2x size buffers
while (fgets(buf, sizeof buf, stdin)) {
char *p = buf;
if (*p++ != '(') {
exit(EXIT_FAILURE);
}
for (i = 0; i < MAXN; i++) {
int n; // use %n to locate scan completion
int cnt = sscanf(p, " (%d ,%d ) %n", &xx[i].a, &xx[i].b, &n);
fprintf(stderr, "cnt = %d '%s'\n", cnt, p);
if (cnt != 2) {
exit(EXIT_FAILURE);
}
p += n;
if (p[0] != ',') {
if (p[0] == ')') {
i++;
break; // Successfully reached the end
}
exit(EXIT_FAILURE);
}
p++;
}
int j;
for (j=0; j< i; j++) {
printf("%d (%d ,%d )\n", j, xx[j].a, xx[j].b);
}
}
}
#3
1
The reason you got strange characters is that scanf()
does not return the scanned value, it returns the number of items that matched the format.
你得到奇怪字符的原因是scanf()不返回扫描值,它返回与格式匹配的项目数。
You are invoking scanf()
in a way that invokes undefined behavior. It expects a pointer to an integer as a parameter when you use the "%d"
specifier, so the correct way would be
您正在以调用未定义行为的方式调用scanf()。当你使用“%d”说明符时,它期望一个指向整数的指针作为参数,所以正确的方法是
if (scanf("%d", &arr[i].x) == 1)
/* succesful */
else
/* error */
The *scanf()
family of functions, are not capable of matching the pattern you want, either use a regular expressions library, or parse the string by splitting the (value, value)
and then their contents separately.
* scanf()系列函数不能匹配您想要的模式,要么使用正则表达式库,要么通过拆分(value,value)然后分别拆分它们的内容来解析字符串。
One way that comes to my mind is to use strtok()
with "),"
but that wouldn't count the last element and would easily fail if there is a white space between the ")"
and ","
so, a state machine and parsing the string one character at a time might be the best way to do it.
我想到的一种方法是使用带有“)的strtok(),”但这不会计算最后一个元素,并且如果“)”和“,”之间存在空白,则很容易失败,因此,状态机器和解析字符串一次一个字符可能是最好的方法。
This is an example of what I mean, I enjoyed writing this
这是我的意思的一个例子,我喜欢写这个
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct point
{
int x;
int y;
};
struct stack
{
char *top;
char **stack;
size_t count;
size_t size;
};
void
stackinit(struct stack *stack)
{
if (stack == NULL)
return;
stack->top = NULL;
stack->stack = NULL;
stack->count = 0;
stack->size = 0;
}
void
stackfinish(struct stack *stack)
{
if (stack == NULL)
return;
free(stack->stack);
stack->stack = NULL;
}
char *
stacktop(struct stack *stack)
{
if ((stack == NULL) || (stack->count == 0))
return NULL;
return stack->stack[stack->count - 1];
}
void
stackpush(struct stack *stack, char *value)
{
void *pointer;
if (stack == NULL)
return;
if (stack->size == stack->count)
{
pointer = realloc(stack->stack, (stack->size + 100) * sizeof(char *));
if (pointer == NULL)
return;
stack->stack = pointer;
stack->size += 100;
}
if (stack->stack == NULL)
return;
stack->stack[stack->count] = value;
stack->count += 1;
}
void
stackpop(struct stack *stack)
{
if ((stack == NULL) || (stack->count <= 0))
return;
stack->count -= 1;
stack->stack[stack->count] = NULL;
}
void
extractpoint(char *string, struct point **points, size_t *count)
{
struct point point;
void *pointer;
char *tail;
if ((string == NULL) || (points == NULL) || (count == NULL))
return;
tail = strchr(string, ')');
if (tail == NULL)
return;
if (sscanf(string, "%d,%d", &point.x, &point.y) != 2)
return;
pointer = realloc(*points, (1 + count[0]) * sizeof(*points));
if (pointer == NULL)
return;
points[0] = pointer;
points[0][count[0]++] = point;
}
void
parse(char *input, struct point **points, size_t *count)
{
struct stack stack;
stackinit(&stack);
while (*(input++) != '\0')
{
char *top;
switch (*input)
{
case '(':
stackpush(&stack, input + 1);
break;
case ')':
stackpop(&stack);
break;
case ',':
top = stacktop(&stack);
if (top == NULL)
continue;
extractpoint(top, points, count);
break;
default:
break;
}
}
stackfinish(&stack);
return;
}
int
main(void)
{
char input[] = "((1828,299),((2729,2553),(2797,2929),(2200,1383),(2894,876))";
size_t count = 0;
struct point *points = NULL;
size_t index = 0;
parse(input, &points, &count);
for (index = 0 ; index < count ; ++index)
fprintf(stdout, "%zu: %d, %d\n", index, points[index].x, points[index].y);
free(points);
return 0;
}
#1
1
#include <stdio.h>
#include <stdlib.h>
struct x{
int a;
int b;
};
int count(const char *s){
if(s == NULL || *s != '(')
return 0;//bad
int n, a, b, count = 0;
for(;;){
n = -1;
if(2!=sscanf(++s, "(%d,%d)%n", &a, &b, &n) || n < 0){
return 0;
} else {
s += n;
++count;
if(*s == ',')
continue;
else if(*s == ')')
return count;
else
return 0;
}
}
}
void set(struct x *a, const char *s){
int n, c = 0;
while(2==sscanf(++s, "(%d,%d)%n", &a[c].a, &a[c].b, &n)){
s += n;
++c;
}
}
int main(void) {
char *input = "((1828,299),(2729,2553),(2797,2929),(2200,1383),(2894,876))";
int i, n = count(input);
if(n == 0){
printf("invalid format!\n");
exit(EXIT_FAILURE);
}
struct x arr[n];
set(arr, input);
for(i = 0; i < n; ++i){
printf("(%4d, %4d)\n", arr[i].a, arr[i].b);
}
return 0;;
}
#2
3
Incorrect use of scanf()
scanf()的使用不正确
-
scanf("%[^, ()],%d", ...)
expects to scan and form a string ("%[^, ()]"
) and anint
("%d"
). Code only provided for a place to save theint
.scanf(“%[^,()],%d”,...)期望扫描并形成一个字符串(“%[^,()]”)和一个int(“%d”)。代码仅提供用于保存int的位置。
-
Code did not check the return value form
scanf()
, so code if not aware of any scanning issues.代码没有检查scanf()的返回值,所以代码如果不知道任何扫描问题。
When data is a line, recommend to use fgets()
, then parse it. Could use strtok() strtol() sscanf()
. Various pros/cons to each. Example:
当数据是一行时,建议使用fgets(),然后解析它。可以使用strtok()strtol()sscanf()。每个人的各种利弊。例:
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#define MAXN (5)
// maximum size needed to print and `int`
#define INTSIZE (sizeof (int )* CHAR_BIT / 3 + 3)
// Expect buffer size needed
#define EXPECTEDSIZE (1+(2*INTSIZE + 4) + 3)
void fooo() {
int i;
struct x {
int a;
int b;
} xx[MAXN];
char buf[EXPECTEDSIZE * 2]; // I favor 2x size buffers
while (fgets(buf, sizeof buf, stdin)) {
char *p = buf;
if (*p++ != '(') {
exit(EXIT_FAILURE);
}
for (i = 0; i < MAXN; i++) {
int n; // use %n to locate scan completion
int cnt = sscanf(p, " (%d ,%d ) %n", &xx[i].a, &xx[i].b, &n);
fprintf(stderr, "cnt = %d '%s'\n", cnt, p);
if (cnt != 2) {
exit(EXIT_FAILURE);
}
p += n;
if (p[0] != ',') {
if (p[0] == ')') {
i++;
break; // Successfully reached the end
}
exit(EXIT_FAILURE);
}
p++;
}
int j;
for (j=0; j< i; j++) {
printf("%d (%d ,%d )\n", j, xx[j].a, xx[j].b);
}
}
}
#3
1
The reason you got strange characters is that scanf()
does not return the scanned value, it returns the number of items that matched the format.
你得到奇怪字符的原因是scanf()不返回扫描值,它返回与格式匹配的项目数。
You are invoking scanf()
in a way that invokes undefined behavior. It expects a pointer to an integer as a parameter when you use the "%d"
specifier, so the correct way would be
您正在以调用未定义行为的方式调用scanf()。当你使用“%d”说明符时,它期望一个指向整数的指针作为参数,所以正确的方法是
if (scanf("%d", &arr[i].x) == 1)
/* succesful */
else
/* error */
The *scanf()
family of functions, are not capable of matching the pattern you want, either use a regular expressions library, or parse the string by splitting the (value, value)
and then their contents separately.
* scanf()系列函数不能匹配您想要的模式,要么使用正则表达式库,要么通过拆分(value,value)然后分别拆分它们的内容来解析字符串。
One way that comes to my mind is to use strtok()
with "),"
but that wouldn't count the last element and would easily fail if there is a white space between the ")"
and ","
so, a state machine and parsing the string one character at a time might be the best way to do it.
我想到的一种方法是使用带有“)的strtok(),”但这不会计算最后一个元素,并且如果“)”和“,”之间存在空白,则很容易失败,因此,状态机器和解析字符串一次一个字符可能是最好的方法。
This is an example of what I mean, I enjoyed writing this
这是我的意思的一个例子,我喜欢写这个
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct point
{
int x;
int y;
};
struct stack
{
char *top;
char **stack;
size_t count;
size_t size;
};
void
stackinit(struct stack *stack)
{
if (stack == NULL)
return;
stack->top = NULL;
stack->stack = NULL;
stack->count = 0;
stack->size = 0;
}
void
stackfinish(struct stack *stack)
{
if (stack == NULL)
return;
free(stack->stack);
stack->stack = NULL;
}
char *
stacktop(struct stack *stack)
{
if ((stack == NULL) || (stack->count == 0))
return NULL;
return stack->stack[stack->count - 1];
}
void
stackpush(struct stack *stack, char *value)
{
void *pointer;
if (stack == NULL)
return;
if (stack->size == stack->count)
{
pointer = realloc(stack->stack, (stack->size + 100) * sizeof(char *));
if (pointer == NULL)
return;
stack->stack = pointer;
stack->size += 100;
}
if (stack->stack == NULL)
return;
stack->stack[stack->count] = value;
stack->count += 1;
}
void
stackpop(struct stack *stack)
{
if ((stack == NULL) || (stack->count <= 0))
return;
stack->count -= 1;
stack->stack[stack->count] = NULL;
}
void
extractpoint(char *string, struct point **points, size_t *count)
{
struct point point;
void *pointer;
char *tail;
if ((string == NULL) || (points == NULL) || (count == NULL))
return;
tail = strchr(string, ')');
if (tail == NULL)
return;
if (sscanf(string, "%d,%d", &point.x, &point.y) != 2)
return;
pointer = realloc(*points, (1 + count[0]) * sizeof(*points));
if (pointer == NULL)
return;
points[0] = pointer;
points[0][count[0]++] = point;
}
void
parse(char *input, struct point **points, size_t *count)
{
struct stack stack;
stackinit(&stack);
while (*(input++) != '\0')
{
char *top;
switch (*input)
{
case '(':
stackpush(&stack, input + 1);
break;
case ')':
stackpop(&stack);
break;
case ',':
top = stacktop(&stack);
if (top == NULL)
continue;
extractpoint(top, points, count);
break;
default:
break;
}
}
stackfinish(&stack);
return;
}
int
main(void)
{
char input[] = "((1828,299),((2729,2553),(2797,2929),(2200,1383),(2894,876))";
size_t count = 0;
struct point *points = NULL;
size_t index = 0;
parse(input, &points, &count);
for (index = 0 ; index < count ; ++index)
fprintf(stdout, "%zu: %d, %d\n", index, points[index].x, points[index].y);
free(points);
return 0;
}