有一段时间我在验证char数组时遇到了问题。我已经看到很多很好的方法可以做到这一点,但仍然没有弄清楚如何在我的代码中组合一些东西。 无法弄清楚如何正确解决这个简单的问题。
struct student{
char fullname[SLEN];
char hobby[SLEN];
int ooplevel;
};
int getinfo( student*, int );
void display1( student );
void display2( const student* );
void display3( const student pa[], int );
int main()
{
std::cout << "Group size: ";
int class_size;
std::cin >> class_size;
while( std::cin.get() != '\n' )
continue;
student* ptr_stu = new student[class_size];
int entered = getinfo( ptr_stu, class_size );
for( int i=0; i<entered; ++i )
{
display1( ptr_stu[i] );
display2( &ptr_stu[i] );
}
display3( ptr_stu, entered );
delete [] ptr_stu;
std::cout << "Gotowe.\n";
getchar();
return 0;
}
int getinfo( student* stu, int n )
{
int i=0;
while( i<n ){
std::cout << "Fullname " << i+1 << ": ";
std::cin >> stu[i].fullname;
std::cout << "Hobby " << i+1 << ": ";
std::cin >> stu[i].hobby;
std::cout << "OOPlevel " << i+1 << ": ";
std::cin >> stu[i].ooplevel;
++i;
}
}
我确定必须有办法验证char数组:
1.最大长度为30
2.必须包含2个单词,因为其第一个和第二个名称为
3.不能包含数字
4.如果用户按下回车而没有输入任何内容,则会导致断开循环
5.一切都在功能中,其中一个参数是指向存储名称的结构的指针
请原谅我这样的原始问题。我知道甚至没有尝试在我的代码中解决这个问题,但我还没有想过要把我在这里创建的垃圾放进去。
答案 0 :(得分:0)
- 最大长度为30
醇>
std::cin >> std::setw(30) >> ...;
- 必须包含2个字,因为其第一个和第二个名称
醇>
operator>>
运气不好,将停在空白处。因此,您需要阅读两次或者阅读完整的一行(std::getline
)。
- 不能包含数字
醇>
好吧,迭代字符串并用isdigit
检查每个字符:
for(unsigned char c : theString)
{
if(isdigit(c))
// error!
}
- 如果用户按Enter键而不键入任何内容
,则会导致循环中断 醇>
再次,operator>>
运气不好 - 它只会忽略空格,包括换行符......再次,你需要std::getline
:
std::string s;
std::getline(std::cin, s);
if(s.empty())
break; // or return
不确定这是不是一个好主意,因为用户可能会意外地输入。那么用户只进入空白区呢? Line非空,但仍然不包含任何信息...
- 一切都在函数中,其中一个参数是指向将存储名称的结构的指针。
醇>
不确定你的意思 - 你已经有了getInfo,不是吗?
您可能会发现并非所有上述内容都很好,例如: G。获取空行仅适用于std::getline
,因此您必须始终使用它...
现在想知道 - 您使用C ++ - 为什么不使用C ++标准容器?它们让您的生活更轻松:
struct Student
{
std::string fullName; // I personally would prefere surname and forename anyway...
std::string hobby;
// ...
}
int getInfo(std::vector<Student>& students)
{
for(auto& student : students)
// ^ enforce reference to actually modify the objects in the vector
{
// read input...
}
// you should return something!!!
return students.size();
}
好的,对于过早的循环退出,我们需要一个返回值 - 我们可以从vector providinig连续内存中获利,所以以下是有效的:
if(emptyLine)
return &student - students.data();
学生姓名:
// we don't need any additional buffer, can read into target directly...
std::getline(std::cin, student.fullName);
auto i = student.fullName.begin(), j = i;
while(isspace((unsigned char)(*i))
++i;
while(!isspace((unsigned char)(*i))
{
if(isdigit((unsigned char)(*i))
// error handling!
*j++ = *i++;
}
*j++ = ' '; // separator
// now sure name analogously!
student.fullName.resize(j - student.fullName.begin());
您可能已经注意到:这会读取整个字符串并对其进行修改。喜欢吗?
上面的代码中还有一些错误,你看到了吗?必须在while循环中检查i != fullName.end()
并在分配分隔空格之前确保不超过字符串的当前范围!我会把它留给你......
您现在应该使用矢量作为显示功能:
void display(std::vector const& students);
// ^ no need for additional identifiers, C++ supports overloads
// ^ const vector, you won't modify it
// ^ reference to prevent a copy
提示循环:
for(auto& student : students)
使用auto关键字可以防止您不必关心const对象。然后引用会阻止您复制数据,因此这是您应该更喜欢的...
类似于一个学生:
void display(Student const& student);
// ^ overload!
// ^ ^ const reference
主要:
//student* ptr_stu = new student[class_size];
//^ replaced by:
std::vector<Student> students(class_size);
// ^ or whatever name you like
// ^ one of vectors constructors accepts a size
// this is then equivalent to:
// std::vector<...> v; v.resize(n);
// ^ (empty vector)
// and no need for deletion either...