- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我需要将这样的学生列表分为ID,姓名和分数。这是一个练习,因此不允许使用字符串,只能使用char
0001 William Bob 8.5
0034 Howard Stark 9.5
0069 Natalia Long Young 8
int readFile(list& a) {
char str[MAX];
short i = 0;
ifstream fi(IN);
if (!fi)
return 0;
while (!fi.eof()) {
fi.getline(str, MAX - 1);
char* temp = strtok(str, " ");
if (temp == NULL)
continue;
strcpy(a.sv[i].id, temp);
temp = strtok(NULL, "0123456789");
strcpy(a.sv[i].name, temp);
temp = strtok(NULL, "\n");
a.sv[i].grade = atof(temp);
i++;
}
a.size = i;
fi.close();
return 1;
}
strtok()
我已成功拆分ID和名称,但得分是
0.5
0.5
0
temp = strtok(NULL, "0123456789");
引起的,但我不知道如何解决,
"0123456789"
旁边是否有任何定界符,还是可以将指针移回?
while(!file.eof())
并解决我的问题的尝试。
#include<iostream>
#include<fstream>
#include<string>
#define IN "D:\\Input.txt"
#define OUT "D:\\Output.txt"
#define MAX 40
using namespace std;
struct sv{
char id[MAX], name[MAX] , sex[MAX];
float grade;
};
struct dssv {
sv sv[MAX];
short size;
};
int readFile(dssv& a) {
char str[MAX];
short i = 0;
ifstream fi(IN);
if (!fi)
return 0;
while (fi>>a.sv[i].id && fi.getline(str, MAX)) {
char* name = strchr(str, ' ');
int pos = strrchr(name, ' ') - name;
char* score = str + pos;
strcpy(name + pos, "\0"); \\null-terminate to remove the score.
strcpy(a.sv[i].name, name + 1);
a.sv[i].grade = atof(score + 1);
i++;
}
a.size = i;
fi.close();
return 1;
}
char* name
和
char* score
而不是一个并重用它。
最佳答案
您从错误的脚开始。请参见Why is while ( !feof (file) ) always wrong?。虽然有多种方法可以将信息分成id, name, score
,但最基本的方法可能是将整个数据行简单地读取到临时缓冲区(字符数组)中,然后使用sscanf
来分隔id, name & score
。
用sscanf
进行解析并不困难,唯一的警告是您的name
可以包含空格,因此您不能简单地使用"%s"
作为格式说明符来提取名称。您的score
字段始终以数字开头,并且名称中不会出现数字(规则总是有例外情况,并且可以使用带有一对指针的简单解析来处理),从而缓解了这种情况示例,我们将对此格式进行假设)
为了简化数据处理并能够将一个学生的所有信息作为一个对象进行协调(允许您创建一个包含所有学生信息的数组),可以使用简单的stuct
。声明一些常量来设置所有内容的大小可以避免在整个代码中使用幻数。 (尽管对于sscanf
字段宽度修饰符,必须使用实际数字,因为您不能对宽度修饰符使用常量或变量。)例如,您的结构可以是:
#define MAXID 8 /* if you need a constant, #define one (or more) */
#define MAXNM 64
#define MAXSTD 128
#define MAXLN MAXSTD
typedef struct { /* simple struct to hold student data */
char id[MAXID];
char name[MAXNM];
double score;
} student_t;
"_t"
后缀用于类型扩展,但不会有
"student_t"
类型-但通常要注意限制,尽管您会经常看到
"_t"
后缀)
fgets
或POSIX
getline
),然后将其传递给
sscanf
。您以成功读取每一行为条件来限制读取循环,以便在达到
EOF
时停止读取。为了用
sscanf
分隔值,使用临时结构保存分隔的值很方便。这样,如果分离成功,则只需将临时结构添加到数组中。要将学生读入
student_t
数组,您可以执行以下操作:
size_t readstudents (FILE *fp, student_t *s)
{
char buf[MAXLN]; /* temporary array (buffer) to hold line */
size_t n = 0; /* number of students read from file */
/* read each line in file until file read or array full */
while (n < MAXSTD && fgets (buf, MAXLN, fp)) {
student_t tmp = { .id = "" }; /* temporary stuct to fill */
/* extract id, name and score from line, validate */
if (sscanf (buf, "%7s %63[^0-9] %lf", tmp.id, tmp.name, &tmp.score) == 3) {
char *p = strrchr (tmp.name, 0); /* pointer to end of name */
/* backup overwriting trailing spaces with nul-terminating char */
while (p && --p >= tmp.name && *p == ' ')
*p = 0;
s[n++] = tmp; /* add temp struct to array, increment count */
}
}
return n; /* return number of students read from file */
}
sscanf
格式字符串:
sscanf (buf, "%7s %63[^0-9] %lf", tmp.id, tmp.name, &tmp.score)
buf
行中,使用的格式字符串为
"%7s %63[^0-9] %lf"
。每种字符数组类型都使用field-width修饰符,以将存储在关联数组中的字符数限制为少于可用字符数。这样可以保护数组边界,并确保所存储的每个字符串都以nul结尾。
"%7s"
是不言自明的-最多将7个字符读为
id
。
"%63[^0-9]"
,因为它使用
"%[...]
字符类转换说明符,并且使用
'^'
作为第一个字符来反转匹配,因此涉及更多。该类中的字符为数字
0-9
,转换说明符最多读取63个不包含数字的字符。这会产生副作用,包括在
name
中
score
和
name
之间的空格。值得庆幸的是,它们很简单,可以通过使用
strrchr (tmp.name, 0);
指向字符串末尾的指针来删除,然后备份以检查字符是否为
' '
(空格)并用一个以n终止的字符(例如
'\0'
)。
0
转换的最后一部分
sscanf
只是
"%lf"
的
double
值的转换说明符。
score
的调用返回是否为
sscanf
来验证转换-请求的转换次数。如果所有转换都成功转换为临时结构
3
,则
tmp
会简单地添加到您的结构数组中。
tmp
调用函数并读取学生信息,您只需声明一个
main()
数组来保存信息,打开并验证您的数据文件已打开以进行读取,然后调用
student_t
捕获返回值验证实际上是从文件中读取了学生信息。然后,您可以根据需要使用数据(以下仅输出):
int main (int argc, char **argv) {
student_t students[MAXSTD] = {{ .id = "" }}; /* array of students */
size_t nstudents = 0; /* count of students */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
/* read students from file, validate return, if zero, handle error */
if ((nstudents = readstudents (fp, students)) == 0) {
fputs ("error: no students read from file.\n", stderr);
return 1;
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
for (size_t i = 0; i < nstudents; i++) /* output each student data */
printf ("%-8s %-24s %g\n",
students[i].id, students[i].name, students[i].score);
return 0;
}
readstudents
和
stdio.h
以及测试:
$ ./bin/read_stud_id_name_score dat/stud_id_name_no.txt
0001 William Bob 8.5
0034 Howard Stark 9.5
0069 Natalia Long Young 8
string.h
字段以数字开头的假设下起作用。
score
,只需声明一对指针即可手动隔离
sscanf
。基本方法是将指针前进到第一个空白并读取
id, name & score
,跳过随后的空白并将指针定位在
id
的开头。从另一行的末尾开始,备份到末尾的第一个空格,并读取
name
,然后继续备份,将指针定位在
score
之后的第一个空格中。然后,只需将开始和结束指针之间的字符复制到
name
并以nul-terminate结束即可。从指针算术的角度来看,它涉及更多,但也很简单。 (留给您)
name
和
vector
类型,并让容器为您处理内存分配)这仅仅是添加一层以增加灵活性,码。
string
和
std::string
的C ++解决方案没有太大区别。这三个值的解析略有不同,将整行读入
std::vector
和
id
,然后从保存在
name
中的那部分行中获取
score
,然后将这些字符从< cc>。
name
更改为
name
,将
FILE*
数组更改为
std::ifstream
,您的
student_t
函数可以写为:
void readstudents (std::ifstream& fp, std::vector<student_t>& s)
{
std::string buf; /* temporary array (buffer) to hold line */
student_t tmp; /* temporary stuct to fill */
/* read each line in file until file read or array full */
while (fp >> tmp.id && getline(fp, tmp.name)) {
/* get offset to beginning digit within tmp.name */
size_t offset = tmp.name.find_first_of("0123456789"),
nchr; /* no. of chars converted with stod */
if (offset == std::string::npos) /* validate digit found */
continue;
/* convert to double, save in tmp.score */
tmp.score = std::stod(tmp.name.substr(offset), &nchr);
if (!nchr) /* validate digits converted */
continue;
/* backup using offset to erase spaces after name */
while (tmp.name.at(--offset) == ' ')
tmp.name.erase(offset);
s.push_back(tmp); /* add temporary struct to vector */
}
}
std::vector<student_t>
,因为返回时可以验证学生向量的
readstudents()
)。
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <vector>
struct student_t { /* simple struct to hold student data */
std::string id;
std::string name;
double score;
};
void readstudents (std::ifstream& fp, std::vector<student_t>& s)
{
std::string buf; /* temporary array (buffer) to hold line */
student_t tmp; /* temporary stuct to fill */
/* read each line in file until file read or array full */
while (fp >> tmp.id && getline(fp, tmp.name)) {
/* get offset to beginning digit within tmp.name */
size_t offset = tmp.name.find_first_of("0123456789"),
nchr; /* no. of chars converted with stod */
if (offset == std::string::npos) /* validate digit found */
continue;
/* convert to double, save in tmp.score */
tmp.score = std::stod(tmp.name.substr(offset), &nchr);
if (!nchr) /* validate digits converted */
continue;
/* backup using offset to erase spaces after name */
while (tmp.name.at(--offset) == ' ')
tmp.name.erase(offset);
s.push_back(tmp); /* add temporary struct to vector */
}
}
int main (int argc, char **argv) {
std::vector<student_t> students {}; /* array of students */
if (argc < 2) { /* validate one argument given for filename */
std::cerr << "error: filename required as 1st argument.\n";
return 1;
}
std::ifstream fp (argv[1]); /* use filename provided as 1st argument */
if (!fp.good()) { /* validate file open for reading */
std::cerr << "file open failed";
return 1;
}
/* read students from file, validate return, if zero, handle error */
readstudents (fp, students);
if (students.size() == 0) {
std::cerr << "error: no students read from file.\n";
return 1;
}
for (auto s : students) /* output each student data */
std::cout << std::left << std::setw(8) << s.id
<< std::left << std::setw(24) << s.name
<< s.score << '\n';
}
关于c++ - 拆分学生列表,其格式如下:0001 William Bill Junior 8.5,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59516918/
我正在实现 lock-free queue Anthony Williams 在“C++ Concurrency in Action”中描述的内容。我将其作为 libcds 的新容器进行测试.弹出和推
请问Esau-Williams 算法在哪些情况下可能有用?我知道它是用来解决CMST问题的,但是我找不到任何可能出现CMST问题的情况。 最佳答案 根据 Wikipedia ,“CMST问题在网络设计
我最近正在开发一个 android 应用程序,我需要使用图表显示一些统计信息。我搜索了 android-arsenal.com,发现了一堆图表库,包括我选择的 William 图表,因为它看起来构建得
我正在尝试将 William Charts 用于我的 Android Studio 项目,但似乎无法导入它。我从 github 下载了 WilliamChart-master zip ,并尝试导入它。
在研究mysql项目时,我未能将JOIN的知识应用到实际情况中,查询本身的逻辑存在问题。 我的目标是进行一个需要 6 个表进行交互的查询。 第一个连接表批处理: CREATE TABLE `books
早上好! 对于无线应用程序,我需要实现各种 CRC 计算。根据规范,CRC 计算应作为移位寄存器实现。 See EPC Spec Ross N. Williams 有一个名为“CRC 错误检测算法的无
假设我正在使用 R ( Bretz et al. (2011) Multiple Comparisons with R. Chapman & Hall/CRC) 的 multcomp 包进行剂量 re
使用regex或Stringtokenizer来分隔此字符串中的作者和标题是否更好: William Faulkner - 'Light In August' 这是最简单的正则表达式吗? Patter
我需要将这样的学生列表分为ID,姓名和分数。这是一个练习,因此不允许使用字符串,只能使用char 0001 William Bob 8.5 0034 Howard Stark 9.5 0069 Nat
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我是一名优秀的程序员,十分优秀!