C++中输入字符数组的特定验证

Specific validation of input char array in C++

本文关键字:验证 数组 输入 字符 C++      更新时间:2023-10-16

一段时间以来,我在正确验证字符数组时遇到了问题。我已经看到了许多很好的方法来做到这一点,但仍然没有弄清楚如何在我的代码中组合一些东西。 不知道如何正确解决这个简单的问题。

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;
}
}

我只是确定必须有办法验证字符数组:
1.最大长度为 30
2。必须包含 2 个单词,因为它的第一个和第二个名称
3.不能包含数字
4。如果用户按 Enter 而不键入任何内容,则会导致中断循环
5.一切都在函数中,其中一个参数是指向将存储名称的结构的指针。
原谅我这个原始的问题。我知道我的代码中甚至没有尝试解决这个问题,但我只是不想把我创建的垃圾放在这里。

  1. 最大长度为 30

std::cin >> std::setw(30) >> ...;

  1. 必须包含 2 个单词,因为它的第一个和第二个名称

运气不好operator>>它会停在空白处。所以你要么需要读两次,要么读一整行(std::getline(。

  1. 不能包含数字

好吧,遍历字符串并用isdigit检查每个字符:

for(unsigned char c : theString)
{
if(isdigit(c))
// error!
}
  1. 如果用户按 Enter 键而不键入任何内容,则会导致中断循环

同样,operator>>运气不好 - 它只会忽略空格,包括换行符......同样,您需要std::getline

std::string s;
std::getline(std::cin, s);
if(s.empty())
break; // or return

不过,不确定这是否是一个好主意,因为用户可能会意外地按回车键。那么用户只输入空白怎么办?行为非空,但仍然不包含任何信息...

  1. 一切都在函数中,其中一个参数是指向将存储名称的结构的指针。

不确定你的意思 - 你已经有了 getInfo,不是吗?

您可能会发现并非上述所有内容都能很好地组合,例如,获取空行仅适用于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();
}

好的,对于过早退出循环,我们需要一个返回值 - 我们可以从向量提供的连续内存中获利,因此以下内容是有效的:

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 关键字可以防止您关心对象是否是常量。然后,引用会阻止您复制数据,因此这是您应该首选的...

类似地,对于单个学生:

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...