C++ 学习拾遗 —— 点滴记录C++学习过程中遇到的问题以及整理
2013.5.28 delete []str;
今天在看老师课件的时候,看到析构函数里有一条语句:
delete []str;
有印象,但一时想不起来。遂查询了一下。
解释:
delete str1; //释放指针变量的内存
delete [] str1; //释放指针数组的内存(说是指针数组,也不是很准确)
指针数组:
在C语言和C++语言中,数组元素全为指针的数组称为指针数组。
一维指针数组的定义形式为:“类型名 *数组标识符[数组长度]”。
例如,一个一维指针数组的定义:int *ptrarray[10]。
也可以:
char *str; //定义一个字符指针
str=new char[20]; //以数组的形式赋给str一片内存
delete []str; //释放字符指针数组的内存
今天查 string& ,看到个帖子不错。
上面的解释:
“string& 是返回引用,这个是C++的特有语法,返回引用的好处和指针类似,就是为了避免返回对象(构造函数等额外开销),提高程序效率。而且,引用和指针又不完全一样,它有其特殊的优点,可以参看C++Primmer中引用和指针的区别相关阐述。”
下面接着有人提问:
string& trim_string(string &s, const char *chars)
main()
{
trim_string("1234", '5');
}
这样调用出了问题啊,是“1234”这里错了,那我应该怎么改呢?
解释:
“你传的是const值,函数接受的是非const值,不行
要么把"1234"定义成std::string
要么把原来函数里面的参数写成const的 ”
当返回一个变量时,会产生拷贝。当返回一个引用时,不会发生拷贝。
2013.5.29 常成员函数
常见形式:
const Time t1; ||
Time const t1; &&
void get_time() const;
性质:
1.常成员函数不能更新对象的数据成员
2.当一个对象被声明为常对象,则不能通过该对象调用该类中的非const成员函数
2013.8.2 数组初始化总结
整型数组初始化:
char a[3][4]={0};
字符数组初始化:
int b[3][4]={0};
布尔型数组初始化:
bool c[5]={0};
结构体初始化:
struct instruction{ //定义结构体,存储指令
int head; //识别指令
int d;
int n; //指令附加内容
}pro[1000]={0}; //存储程序体,相当于RAM
初始化之后都会变成0。
(char数组变为\000,int数组变为0,bool数组变为false,这个例子里的结构体所有元素的每一个成员值都为0)
2013.8.6 二维数组的引用作为函数参数传值
样例 1:
1 #include <iostream>
2 #include <cstring>
3 using namespace std;
4
5 char words[1000][17]={0};
6 char ci[100][17]={0};
7
8 void decipher(char (&words)[17],char (&ci)[17]) //将二维数组作为一维数组传递进来
9 {
10 cout<<words<<endl; //words[0]
11 cout<<(words+17)<<endl; //words[1]
12 }
13
14 int main()
15 {
16 strcpy(words[0],"C++");
17 strcpy(words[1],"Java");
18 decipher(words[0],ci[0]);
19 return 0;
20 }
样例 2:
1 #include <iostream>
2 #include <cstring>
3 using namespace std;
4
5 char words[1000][17]={0};
6 char ci[100][17]={0};
7
8 void decipher(char (&words)[1000][17],char (&ci)[100][17])//将二维数组的引用直接传递进来
9 {
10 cout<<*words<<endl; //words[0]
11 cout<<*(words+1)<<endl; //words[1]
12 }
13 int main()
14 {
15 strcpy(words[0],"C++");
16 strcpy(words[1],"Java");
17 decipher(words,ci);
18 return 0;
19 }
注意利用两种方式输出的不同,还有给words[0]和words[1]赋值的方式。
输出结果都是:
C++
Java
2013.8.6 C++错误提示
stray '\241' in program :该错误是指源程序中有非法字符,需要去掉非法字符。中文空格,中文引号, 中文各种标点符号,都会出现。
2013.8.7 C++ string 成员函数
assign() —— 赋值
C++ string类的成员函数,用于拷贝、赋值操作,它们允许我们顺次地把一个string 对象的部分内容拷贝到另一个string 对象上。
有时候我们需要把一个字符串上的部分内容赋值给另一个字符串,而又觉得用for循环依次拷贝麻烦,这时候使用assign()函数就很方便了。个人认为是个很实用的string成员函数,记下来比较好。
1、string s1( "Mississippi" ); string s3;
// 拷贝s1 的前4 个字符
s3.assign( s1, 0, 4 );
s3 现在的值为“Miss”。
2、 string str1, str2 = "War and Peace";
str1.assign( str2, 4, 3 );
cout << str1 << endl;
显示
and
2013.8.28 关于cin过滤
cin会过滤掉治表符,回车和空格的输入,cin输入默认分隔符是空格或者回车,也可以设置分隔符。
例如:
while(cin>>c){
cout<<' '<<c;
}
与
while(c=getchar()){
cout<<' '<<c;
}
同时输入“123”并回车。
123
比较输出结果
前者:
1 2 3
后者为:
1 2 3
仔细观察会发现后者比前者多一行。这说明前者使用cin的从标准输入中读入数据的时候将回车过滤掉了,而后者使用getchar依次读取缓冲区中的字符然后输出,自然将回车也读入了。
两者都是输入的时候在控制台中打上一行字符串“123”,然后回车。按下回车的时候,就将字符串包括后面的回车符都放入到了键盘缓冲区里面,区别就是从缓冲区里面向外读的时候,cin忽略掉了回车符,而getchar照常读入。
这时候使用cin的要注意,缓冲区里面还残留着一个回车符,这在一些情况下,容易因为疏忽出现问题。
样例:
1 #include <iostream>
2 #include <string>
3 using namespace std;
4
5 int main()
6 { //用getline()读入n行字符串,并输出
7 int n;
8 string s[100];
9 cin>>n; //读入n
10 cout<<"input:"<<endl;
11 for(int i=0;i<n;i++) //读入字符串
12 getline(cin,s[i]);
13 cout<<"output:"<<endl;
14 for(int i=0;i<n;i++) //依次输出字符串
15 cout<<s[i]<<endl;
16 return 0;
17 }
结果会出现这种情况:
3
input:
123
456
output:
123
456
第三行字符串还没输入的时候,结果就直接输出出来了,并且输出结果的开头还多出一空行。
原因就是读入整数n之后缓冲区里,还残留着一个回车符。所以getline会先读取回车符作为第一行字符串。
将代码改成这样就行了:
1 #include <iostream>
2 #include <stdio.h>
3 #include <string>
4 using namespace std;
5
6 int main()
7 { //用getline()读入n行字符串
8 int n;
9 string s[100];
10 cin>>n; //读入n
11 getchar(); //将回车符消除
12 //注:C++中fflush(stdin)是清除文件缓冲区,文件以写方式打开时将缓冲区内容写入文件
13 cout<<"input:"<<endl;
14 for(int i=0;i<n;i++) //读入字符串
15 getline(cin,s[i]);
16 cout<<"output:"<<endl;
17 for(int i=0;i<n;i++) //依次输出字符串
18 cout<<s[i]<<endl;
19 return 0;
20 }
正确输入结果:
3
input:
123
456
789
output:
123
456
789
2013.9.8 char类型数据
今天发现一个平时没注意的细节,char字符类型默认是有符号型,也就是要拿出一位来存储正负号,这样1个char型数据所代表的数据范围就是128。
注意这个知识点,再看下面的例子。
#include <iostream>
using namespace std;
int main()
{
char c='z';
char t=c+10;
if(t>'z') //如果加10赋值后会再判断,t的值会超过127,转换成char就会砍掉一部分,输出就会出错
cout<<char(t-26)<<endl;
else
cout<<char(t)<<endl;
/* 像这样直接+10再比较就不会自动转换,或者将上面的t改成 unsigned char 类型也可以
if(c+10 > 'z')
cout<<char(c-26)<<endl;
else
cout<<char(c)<<endl;
*/
return 0;
}
2013.12.17 C++的输出格式控制 - float数小数点显示位数
1 #include <iostream>
2 #include <iomanip> //C++的格式控制头文件
3 using namespace std;
4
5 int main()
6 {
7 float M;
8 int N;
9 cin>>M>>N;
10 float sum=0;
11 while(N--){
12 sum+=M/2+M;
13 M/=2;
14 }
15 cout<<setiosflags(ios::fixed); //带小数点的形式显示浮点数
16 cout<<setprecision(2); //和setiosflags(ios::fixed)合用就是控制浮点数显示的小数点位数
17 cout<<M<<' '<<sum-M<<endl;
18 return 0;
19 }
另:setprecision(6)可以恢复输出默认小数点位数。
2013.12.26 time.h头文件的测试学习
1 #include <iostream>
2 #include <time.h>
3 #include <stdio.h>
4 #include <windows.h>
5 using namespace std;
6 int main()
7 {
8 time_t t = time(NULL);
9 cout<<"从1970年1月1日到现在过去了 ";
10 cout<<t/(365*24*60*60)<<" 年"<<endl<<endl;
11
12 cout<<"char* ctime(time_t*)函数的使用,得到日历时间"<<endl;
13 char* ct = ctime(&t); //得到日历时间
14 cout<<ct<<endl;
15
16 cout<<"利用 struct tm* 结构体输出时间"<<endl;
17 tm* curt = localtime(&t);
18 cout<<1900 + curt->tm_year<<"年"
19 <<1 + curt->tm_mon<<"月" //该月份tm_mon范围为0~11
20 <<curt->tm_mday<<"日"<<endl<<endl;
21
22 cout<<"struct tm* gmtime(time_t*)函数的使用,得到GMT时间,同样也是返回tm结构体"<<endl;
23 tm* curt2 = gmtime(&t);
24 cout<<1900 + curt2->tm_year<<"年"
25 <<1 + curt2->tm_mon<<"月" //该月份tm_mon范围为0~11
26 <<curt2->tm_mday<<"日"<<endl<<endl;
27
28 cout<<"char* asctime(tm*)函数的使用,得到机器时间,可将tm结构体转换为char*字符串"<<endl;
29 char* ct2= asctime(curt); //得到机器时间
30 cout<<ct2<<endl<<endl;
31
32 cout<<"void tzset(void)函数的使用,用于得到时区"<<endl;
33 tzset();
34 time(&t);
35 cout<<asctime(localtime(&t))<<endl<<endl;
36
37 cout<<"double difftime(time_t,time_t)函数的使用,得到两次机器时间差"<<endl;
38 //delay(2000); //本来想用此函数延时,编译总是不通过,后来一查才知道此函数是TC下用的,要加doc.h头文件,但是codeblocks环境下好像没有该头文件,现在都用Sleep()函数延时。
39 //Sleep(2000); //等待2秒,头文件 windows.h,注意开头必须是大写 S
40 getchar(); //等待用户时间,头文件 stdio.h
41 time_t t2 = time(NULL);
42 double cha_t = difftime(t2,t); //输出单位是秒
43 cout<<cha_t<<endl<<endl;
44
45 return 0;
46 }
输出结果截图:
另可参见该博文:C++时间标准库时间time和系统时间的使用
2013.12.26 c/c++随机数生成
random - 百度百科:http://baike.baidu.com/view/1559898.htm
c生成随机数:http://www.cnblogs.com/xiangzi888/archive/2012/04/21/2462300.html
C/C++产生随机数:http://blog.csdn.net/beyond0824/article/details/6009908
2013.12.26 利用fflush()函数刷新缓冲区
引自“fflush - 百度百科” ————
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout<<12345.0<<endl;//输出"12345"
cout<<setiosflags(ios::fixed)<<setprecision(3)<<1.2345<<endl;//输出"1.234"(遵循 四舍六入五成双 的原则,而不是四舍五入的原则)
cout<<setiosflags(ios::scientific)<<12345.0<<endl;//输出"1.234500e+004 "
cout<<setprecision(3)<<12345.0<<endl;//输出"1.23e+004 "
return 0;
}
注意代码中注释部分有提到控制浮点数输出位数的函数是按照“四舍六入五成双”规则来舍位的,那么什么是“四舍六入五成双”规则呢?下面是它的解释:
四舍六入五成双:
对于位数很多的近似数,当有效位数确定后,其后面多余的数字应该舍去,只保留有效数字最末一位,这种修约(舍入)规则是“四舍六入五成双”,也即“4舍6入5凑偶”这里“四”是指≤4 时舍去,"六"是指≥6时进上,"五"指的是根据5后面的数字来定,当5后有数时,舍5入1;当5后无有效数字时,需要分两种情况来讲:①5前为奇数,舍5入1;②5前为偶数,舍5不进。(0是偶数)
2013.12.29 printf("%.*s",str); 字符串输出宽度控制
直接上代码:
1 #include <stdio.h>
2
3 int main()
4 {
5 char str[] = "123456";
6 printf("%s\n%.3s\n",s,s);
7 //"%.*s",点后面的数字代表输出的宽度,多余的部分不会显示。默认左对齐
8 return 0;
9 }
输出结果为:
123456
123
2013.12.29 "%*c"的解释
scanf("%*c");
读入一个字符,但是不将它赋给任何变量,即读入的时候跳过一个字符。
同样也有
scanf("%*d");
表示读入一个整型数,但是不将它赋给任何变量。
样例:
#include <stdio.h>
int main()
{
int a,b,c;
scanf("%d %*d %d",&a,&b,&c); //跳过输入时第二个整型数
printf("%d %d %d",a,b,c); //依次输出三个整型数的值
return 0;
}
输入:
1 2 3
输出:
1 3 5382608
2013.12.29 freopen("CON","w",stdout); 之后执行 system("cls"); 等系统命令出现乱码的问题
样例 1:
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main()
5 {
6 freopen("CON","w",stdout); //重定向为控制台输出“CON”
7 printf("I love China!\n");
8 system("cls");
9 return 0;
10 }
输出结果:
出现乱码。
样例 2:
这样的情况容易在写关于文件控制和控制台控制相关的程序的时候出现错误,像在控制台下的学生信息录入系统:
进入【1】,录入一个学生信息,用 freopen() 写入到一个文件中,然后用system(“cls”);清屏返回主界面的时候:
输出出现乱码。
这是因为标准输出stdout的句柄信息发生了改变。
freopen重定向为CON控制台输出之后再调用任何系统命令就会产生乱码错误,因为在重定向过程中将“标准输出”变成了“控制台输出”,虽然两者体现形式都是在控制台上显示,但本质上是不同的。
所以恢复原来的输入输出就可以。
修改方法
【1】保存原来标准输出的句柄,待要恢复的时候,直接将原来的句柄复制回去。
具体为:
增加一个头文件
#include <io.h>
保存
#define STDOUT 1
int oldstdout = dup(STDOUT); //保存标准输出的句柄
恢复
dup2(oldstdout,STDOUT); //恢复句柄
注意:
0,1,2是三个保留的句柄,分别代表stdin、stdout、stderr。
【2】直接用改用fopen()操作文件。
样例2源代码:
错误代码:
1 /* 2 用C语言编写一个系统 3 要求: 4 1.录入某学生的学生证信息。 5 2.给定学号,显示某位学生的学生证信息。 6 3.给定某个班级的班号,显示该班所有学生的学生证信息。 7 4.给定某位学生的学号,修改该学生的学生证信息。 8 5.给定某位学生的学号,删除该学生的学生证信息。 9 6.给定某个班级的班号,显示该班的学生人数。 10 [ 提示 ] 11 1.定义结构体表示学生证信息(学号,姓名,性别,班级号,专业)。 12 2.用文件储存学生证信息。 13 3.分别定义函数实现上述各功能。 14 4.在main函数中调用上述函数进行演示。 15 */ 16 #include <stdio.h> 17 #include <string.h> 18 #include <stdlib.h> 19 struct Student_card{ 20 char num[15]; 21 char name[10]; 22 char sex[3]; 23 char Class[20]; 24 char major[30]; 25 }; 26 void Input_info() 27 { 28 struct Student_card stu; 29 while(1){ 30 //输入学生信息 31 printf("请输入学号:"); 32 scanf("%s",stu.num); 33 printf("请输入姓名:"); 34 scanf("%s",stu.name); 35 printf("请输入性别:"); 36 scanf("%s",stu.sex); 37 printf("请输入班级:"); 38 scanf("%s",stu.Class); 39 printf("请输入专业:"); 40 scanf("%s",stu.major); 41 //将信息写入到文件尾 42 char file[20]; 43 strcpy(file,stu.Class); 44 int l; 45 for(l=0;file[l]!='\0';l++); 46 char *p=file; 47 strcat(file+l,".txt"); 48 if(freopen(file,"a",stdout)==NULL){ 49 fprintf(stderr,"%.txt数据存储文件打开失败",stu.Class); 50 continue; //如果打开文件失败,退出本次循环 51 } 52 printf("%s\t%s\t%s\t%s\t%s\n",stu.num,stu.name,stu.sex,stu.Class,stu.major); 53 freopen("CON","w",stdout); //恢复默认的stdout(控制台输出) 54 //提问是否继续录入信息 55 getchar(); 56 while(1){ 57 printf("是否继续录入下一位同学?(y / n)"); 58 char sel; 59 scanf("%c",&sel); 60 if(sel=='y' || sel=='Y'){ 61 break; 62 } 63 else if(sel=='n' || sel=='N'){ 64 return ; 65 } 66 } 67 } 68 } 69 void Start() //开始界面,显示各种功能 70 { 71 //读入选择 72 while(1){ 73 int select; 74 printf("[1]录入 学生证信息\n"); //Input_info() 75 printf("[2]显示 某学生学生证信息\n"); //Print_stu() 76 printf("[3]修改 某学生学生证信息\n"); //Change_stu() 77 printf("[4]删除 某学生学生证信息\n"); //Delete_stu() 78 printf("[5]显示 某班级学生证信息\n"); //Print_Class() 79 printf("[6]显示 某班级学生总人数\n"); //Print_Class_num() 80 printf("[7]退出 系统\n"); 81 82 scanf("%d",&select); 83 switch(select){ 84 case 1:system("cls");Input_info();break; 85 //case 2:system("cls");Print_stu();break; 86 //case 3:system("cls");Change_stu();break; 87 //case 4:system("cls");Delete_stu();break; 88 //case 5:system("cls");Print_Class();break; 89 //case 6:system("cls");Print_Class_num();break; 90 case 7:printf("欢迎使用本系统!\n");return ; 91 default:break; 92 } 93 system("cls"); 94 } 95 return ; 96 } 97 void Print_stu(); 98 void Change_stu(); 99 void Delete_stu(); 100 void Print_Class(); 101 void Print_Class_num(); 102 int main() 103 { 104 Start(); 105 return 0; 106 }
方法【1】修改后代码:
1 /* 2 用C语言编写一个系统 3 要求: 4 1.录入某学生的学生证信息。 5 2.给定学号,显示某位学生的学生证信息。 6 3.给定某个班级的班号,显示该班所有学生的学生证信息。 7 4.给定某位学生的学号,修改该学生的学生证信息。 8 5.给定某位学生的学号,删除该学生的学生证信息。 9 6.给定某个班级的班号,显示该班的学生人数。 10 [ 提示 ] 11 1.定义结构体表示学生证信息(学号,姓名,性别,班级号,专业)。 12 2.用文件储存学生证信息。 13 3.分别定义函数实现上述各功能。 14 4.在main函数中调用上述函数进行演示。 15 */ 16 #include <stdio.h> 17 #include <string.h> 18 #include <stdlib.h> 19 #include <io.h> 20 struct Student_card{ 21 char num[15]; 22 char name[10]; 23 char sex[3]; 24 char Class[20]; 25 char major[30]; 26 }; 27 void Input_info() 28 { 29 #define STDOUT 1 30 int oldstdout = dup(STDOUT); 31 struct Student_card stu; 32 while(1){ 33 //输入学生信息 34 printf("请输入学号:"); 35 scanf("%s",stu.num); 36 printf("请输入姓名:"); 37 scanf("%s",stu.name); 38 printf("请输入性别:"); 39 scanf("%s",stu.sex); 40 printf("请输入班级:"); 41 scanf("%s",stu.Class); 42 printf("请输入专业:"); 43 scanf("%s",stu.major); 44 //将信息写入到文件尾 45 char file[20]; 46 strcpy(file,stu.Class); 47 int l; 48 for(l=0;file[l]!='\0';l++); 49 char *p=file; 50 strcat(file+l,".txt"); 51 if(freopen(file,"a",stdout)==NULL){ 52 fprintf(stderr,"%.txt数据存储文件打开失败",stu.Class); 53 continue; //如果打开文件失败,退出本次循环 54 } 55 printf("%s\t%s\t%s\t%s\t%s\n",stu.num,stu.name,stu.sex,stu.Class,stu.major); 56 freopen("CON","w",stdout); //恢复默认的stdout(控制台输出) 57 dup2(oldstdout,STDOUT); 58 //提问是否继续录入信息 59 getchar(); 60 while(1){ 61 printf("是否继续录入下一位同学?(y / n)"); 62 char sel; 63 scanf("%c",&sel); 64 if(sel=='y' || sel=='Y'){ 65 break; 66 } 67 else if(sel=='n' || sel=='N'){ 68 return ; 69 } 70 } 71 } 72 } 73 void Start() //开始界面,显示各种功能 74 { 75 //读入选择 76 while(1){ 77 int select; 78 printf("[1]录入 学生证信息\n"); //Input_info() 79 printf("[2]显示 某学生学生证信息\n"); //Print_stu() 80 printf("[3]修改 某学生学生证信息\n"); //Change_stu() 81 printf("[4]删除 某学生学生证信息\n"); //Delete_stu() 82 printf("[5]显示 某班级学生证信息\n"); //Print_Class() 83 printf("[6]显示 某班级学生总人数\n"); //Print_Class_num() 84 printf("[7]退出 系统\n"); 85 86 scanf("%d",&select); 87 switch(select){ 88 case 1:system("cls");Input_info();break; 89 //case 2:system("cls");Print_stu();break; 90 //case 3:system("cls");Change_stu();break; 91 //case 4:system("cls");Delete_stu();break; 92 //case 5:system("cls");Print_Class();break; 93 //case 6:system("cls");Print_Class_num();break; 94 case 7:printf("欢迎使用本系统!\n");return ; 95 default:break; 96 } 97 98 system("CLS"); 99 } 100 return ; 101 } 102 void Print_stu(); 103 void Change_stu(); 104 void Delete_stu(); 105 void Print_Class(); 106 void Print_Class_num(); 107 int main() 108 { 109 Start(); 110 return 0; 111 }
方法【2】修改后代码:
1 /* 2 用C语言编写一个系统 3 要求: 4 1.录入某学生的学生证信息。 5 2.给定学号,显示某位学生的学生证信息。 6 3.给定某个班级的班号,显示该班所有学生的学生证信息。 7 4.给定某位学生的学号,修改该学生的学生证信息。 8 5.给定某位学生的学号,删除该学生的学生证信息。 9 6.给定某个班级的班号,显示该班的学生人数。 10 [ 提示 ] 11 1.定义结构体表示学生证信息(学号,姓名,性别,班级号,专业)。 12 2.用文件储存学生证信息。 13 3.分别定义函数实现上述各功能。 14 4.在main函数中调用上述函数进行演示。 15 */ 16 #include <stdio.h> 17 #include <string.h> 18 struct Student_card{ 19 char num[15]; 20 char name[10]; 21 char sex[3]; 22 char class[20]; 23 char major[30]; 24 }; 25 26 void Input_info(); 27 void Print_stu(); 28 void Change_stu(); 29 void Delete_stu(); 30 void Print_class(); 31 void Print_class_num(); 32 33 int main() 34 { 35 Start(); 36 return 0; 37 } 38 39 void Start() //开始界面,显示各种功能 40 { 41 //读入选择 42 while(1){ 43 int select; 44 printf("[1]录入 学生证信息\n"); //Input_info() 45 printf("[2]显示 某学生学生证信息\n"); //Print_stu() 46 printf("[3]修改 某学生学生证信息\n"); //Change_stu() 47 printf("[4]删除 某学生学生证信息\n"); //Delete_stu() 48 printf("[5]显示 某班级学生证信息\n"); //Print_class() 49 printf("[6]显示 某班级学生总人数\n"); //Print_class_num() 50 printf("[7]退出 系统\n"); 51 52 scanf("%d",&select); 53 switch(select){ 54 case 1:system("cls");Input_info();break; 55 //case 2:system("cls");Print_stu();break; 56 //case 3:system("cls");Change_stu();break; 57 //case 4:system("cls");Delete_stu();break; 58 //case 5:system("cls");Print_class();break; 59 //case 6:system("cls");Print_class_num();break; 60 case 7:printf("欢迎使用本系统!\n");return ; 61 default:break; 62 } 63 system("CLS"); 64 } 65 return ; 66 } 67 68 void Input_info() 69 { 70 struct Student_card stu; 71 while(1){ 72 //输入学生信息 73 printf("请输入学号:"); 74 scanf("%s",stu.num); 75 fflush(stdin); 76 printf("请输入姓名:"); 77 scanf("%s",stu.name); 78 fflush(stdin); 79 printf("请输入性别:"); 80 scanf("%s",stu.sex); 81 fflush(stdin); 82 printf("请输入班级:"); 83 scanf("%s",stu.class); 84 fflush(stdin); 85 printf("请输入专业:"); 86 scanf("%s",stu.major); 87 fflush(stdin); 88 //将信息写入到文件尾 89 char file[20]; 90 strcpy(file,stu.class); 91 int l; 92 for(l=0;file[l]!='\0';l++); 93 char *p=file; 94 strcat(file+l,".txt"); 95 FILE* fp; 96 if((fp=fopen(file,"a"))==NULL){ 97 fprintf(stderr,"%.txt数据存储文件打开失败",stu.class); 98 continue; //如果打开文件失败,退出本次循环 99 } 100 fprintf(fp,"%s\t%s\t%s\t%s\t%s\n",stu.num,stu.name,stu.sex,stu.class,stu.major); 101 fclose(fp); 102 fp=NULL; 103 //提问是否继续录入信息 104 fflush(stdin); 105 while(1){ 106 printf("是否继续录入下一位同学?(y / n)"); 107 char sel; 108 scanf("%c",&sel); 109 fflush(stdin); 110 if(sel=='y' || sel=='Y'){ 111 break; 112 } 113 else if(sel=='n' || sel=='N'){ 114 return ; 115 } 116 } 117 } 118 } 119 120 void Print_stu() 121 { 122 123 }
相关链接:
百度百科 - dup:http://baike.baidu.com/link?url=ZdGhJiAbyKTZD_tU18xor60-sHqBgyR_92D7UyXbO-hJxxdyvuOyHVRQ9uk_tIGQ#2
百度百科 - dup2:http://baike.baidu.com/link?url=eXA_W9kaUCMrU9Y6E_GjWBbXKuslZBU8b6Akq3FvCbViUefCV8cVFnEOGh75DGsg
2014.1.3 y++=x++ 和 ++y=++x 的区别
从百度知道上看到的一个提问,C++的语法知识:
求助,一道c++赋值表达式的问题
2013-04-23 20:24NF细雨听风 | 来自手机知道 | 分类:C/C++ | 浏览36次
设有定义float x=4,y=2,则下列表达式中,正确的是
A.y++=x++ B.++y=++x
这道题选A还是选B?另外一个为什么不能选呢?我是个刚学c++的新手,麻烦讲的通俗些,详细些,谢谢了~
网友采纳回答:
网友采纳
B。
y++不能被赋值,因此A有语法错误。
++y可以被赋值,这里y先执行++操作,变为3;x执行++操作,变为5,最后将x赋值给y,y的值变为5。
-------------------------------------------------------------
我写了个程序测试了一下:
1 #include <iostream>
2
3 using namespace std;
4
5 int main()
6 {
7 float x=4,y=2;
8 //y++=x++;
9 ++y=++x;
10 cout<<y<<endl;
11 return 0;
12 }
发现第8行注释起来的代码确实不能运行,会编译错误,错误信息为:
error: lvalue required as left operand of assignment
这句话的意思是:表达式中的“=”号左边应该有一个运算符或者变量。
我的理解: A,语法错误,原因如上。B,由于前置的++运算符优先级较高,所以先执行自加运算(++y)和(++x),y和x的值分别变为3和5。然后执行赋值运算,将x的值5赋给变量y,所以y的值变为5。之后输出y的值5。
2014.1.3 二维数组和指针
从网上找的二维数组的指针相关知识:
a[i][j]的地址可用以下五种表达式求得:(1)&a[i][j](2)a[i]+j(3)*(a+i)+j(4)&a[0][0]+4*i+j (5)a[0]+ 4*i+j
例题见:ytu 1050:写一个函数,使给定的一个二维数组(3×3)转置,即行列互换
2014.1.16 结构体实例 放在 if()中
例:
1 struct NODE{
2 int x;
3 int y;
4 } cur;
5 cur.x = 0;
6 cur.y = 0;
7 if(cur)
8 cout<<1<<endl;
9 else
10 cout<<0<<endl;
这样默认是不可以的。
可以 重载 == 和 != ,或者非 ! 来实现此功能。
2014.1.20 sqrt()求平方根库函数的使用
不知道有没有同学在一开始使用sqrt()函数的时候遇到这样的错误:
百度百科上的解释为:
VC 2008后为重载函数,原型为 float sqrt (float),double sqrt (double),double long sqrt(double long)
注意没有int sqrt (int)
注意没有 int sqrt(int) 的用法也就是说不能对整型数开方,必须强制转换为浮点型(double、float、double long等)作为实参传递进来。
2014.2.26 char* 和 char (*) [] 的区别
char * 是指向一个char型变量的指针。
char (*)[] 是指向一个char型数组的指针。
例子:
1、获得一个 char * 型指针。
char *mystrcat(char *a,char *b){...}
int main(){
char *c;
char a[1000],b[1000];
c = mystrcat(a,b); //直接赋值
return 0;
}
2、获得一个 char (*)[] 型指针。
char *mystrcat(char *a,char *b){...}
int main(){
char (*c)[1000];
char a[1000],b[1000];
c = (char (*)[1000])mystrcat(a,b); //需要强制转换
return 0;
}
这两个c变量都可以用来输出连接后的字符串。
2014.2.27 引用作函数参数
今天看数据结构的顺序表的实现,其中初始化函数是这样描述的:
void InitList(SqList* &L){...}
其中形参 SqList* &L 这一大串是什么意思呢?
询问过老师,这是一个SqList* L变量的引用。
“引用可以理解为一个常指针。它是一个变量的别名。”
在这里L就是一个指向SqList类型的指针变量的引用。由此看来,其实他跟 int &a = b; 是一个道理,可以对比:
int &a = b; ==> SqList* &L = 实参;
可参考本文另一“引用”介绍: 2013.5.29 返回引用 string&
2014.2.28 带参的宏和模板函数
在C或C++语言源程序中允许用一个标识符来表示一个字符串,称为“宏”。 “define”为宏定义命令。
详情可见练习:
ytu 1057: 输入两个整数,求他们相除的余数(带参的宏 + 模板函数 练习)
2014.2.28 表达式数值溢出
1 int n;
2 cin>>n;
3 cout<<n*(n-1)*(n-2)<<endl;
问题:这里如果n太大,表达式的值就会溢出。
为什么会出现这个问题呢?
编译器在底层对表达式 n*(n-1)*(n-2) 计算的时候,会先将 n 从内存中拿出来,放到寄存器中,因为是int型变量,所以会放到32位寄存器中。之后的运算都在这个寄存中进行,n太大就会导致32位寄存器溢出。
要解决这个问题就需要用long long(codeblocks)型变量,用long long 进行表达式的运算时,会将数据存储到64位寄存器中,数据大了,自然就不容易溢出了。
2014.3.14 char数组如何存储汉字
汉字每一个是占用2个char的。串末尾要加零。所以要3个,2个汉字要5个char。
5个汉字要11个char
char a[11];
char * p = "汉字串数组";
strcpy(a,p);
printf( "%s\n"a);
直接复制了百度知道的回答,这个问题值得收藏。
2014.3.31 复制(拷贝)构造函数的参数为什么必须是引用?
如果参数是非引用,像A=B(A、B是对象),程序要先调用复制构造函数生成一个B的副本c,然后赋给A,但是生成B的副本c的时候又要调用复制构造函数生成一个新的副本d,用以赋给c……这就形成了一个无限递归。显而易见,这是不行的。
而参数是引用的话,直接赋值就行,无需生成副本。
2014.3.31 关于typedef
typedef 是“类型重定向”的意思,就是给一个类型另起一个名字。
例如:
typedef Point Vector;
定义之后,后面使用的时候,Vector就和Point完全一样。
2014.3.31 sort()函数的使用
sort()和qsort()一样,都是对数组的指定部分排序。qsort()只使用了快排,sort()使用了混合排序,相比之下,sort()更快一些。
sort()函数常用的有两种形式,两个参数的形式,和三个参数的形式。
1、两参数:sort(数组名,数组末地址); //例如:sort(a+1,a+n+1);就是对a[1]...a[n+1]进行排序,默认是升序排序,如果想改变排序顺序,需要另写一个比较函数
2、三参数:sort(数组名,数组末地址,比较函数);
例如:
bool cmp(const int a,const int b)
{
return a<b;
}
sort(a+1,a+10+1,cmp);
就是对a[1]...a[n+1]进行从大到小排序。
2014.4.16 删掉原变量,该变量的引用还能使用吗?
创建一个变量的引用,然后将这个变量删掉,那么这个引用还可以使用吗?
答案是否定的。可以用一段代码来测试:
1 #include <iostream>
2 using namespace std;
3 int main()
4 {
5 int a;
6 cin>>a; //输入
7 cout<<endl;
8 int &b = a; //创建原变量的引用
9 //输出
10 cout<<a<<endl;
11 cout<<b<<endl;
12 cout<<endl;
13 delete(&a); //删除原变量
14 //再次输出
15 cout<<a<<endl;
16 cout<<b<<endl;
17 return 0;
18 }
这段代码会删除引用的原变量,程序运行会出错。可见是不行的。
2014.4.30 利用正则表达式 scanf("%[^\n]",str); 读入整行字符串
样例:
1 #include <stdio.h>
2
3 int main()
4 {
5 char str[100];
6 while(scanf("%[^\n]",str)!=EOF){ //读入一行。不会读入最后的'\n'
7 printf("%s\n",str);
8 scanf("%*"); //需要行后的回车读进来
9 }
10 return 0;
11 }
说明:"%[^\n]"表示读入到回车停止,所以会读入整行。
注意:这里的检测是直接对缓冲区检测,也就是说scanf在缓冲区中就确定了要读取的部分,所以'\n'不会像getline()那样读入进来然后扔掉,如果不作处理,它会一直留在缓冲区中。
所以如果没有scanf("%*");吃掉剩下的'\n',整个程序就会陷入死循环,不断的输出str。
备注:scanf("%*");中的'*'是通配符,表示忽略掉一个输入,而不管这个输入是字符还是数。
2014.5.28 memset() 赋值问题
memset(a,0,sizeof(a));
如果a是一个数组,a[1000]中所有的值都设为0.
但是如果这样
#define VAL 0x7fffffff
memset(a,VAL,sizeof(a));
则怎么赋值呢?
memset不会把VAL这个值整个赋给a的每一个元素,而是取0x7fffffff的最后两位,也就是一个字节的值ff不断赋值,这样的话就相当于将0xffffffff赋给每一个元素。
2014.7.28 unique() 去重函数
使用举例:
int len = unique(a,a+len) - a;
这是对数组a进行去重操作,其中len为数组元素个数。参数中的len是原来数组元素个数,前面的len是去重之后的数组元素个数。unique()返回的是去重之后的数组的最后一个元素的地址,这个地址减去初始地址就是去重之后的元素个数。
另外需要注意这个函数去重不是把重复的元素删掉,而是放到后面,这样去重之后,前面部分的元素是不重复的元素,后面部分是重复的元素。
另外因为unique去除的是相邻的重复元素,所以一般使用前都要先排一下序。
2014.12.21 ungetc() 将输入的字符退回到缓冲区
如果你用getchar()从缓冲区获取了一个字符,那么你如何将它再放回到缓冲区,下次输入还是获取到这个字符呢?
可以使用 ungetc() 函数。
ungetc(int c,FILE* stream);
功 能
把一个(或多个)字符退回到输入流中,可以理解成一个“计数器”。
用 法
int ungetc(int c, FILE *stream);
输入参数
c 要写入的字符,stream 文件流指针
输出参数
字符c - 操作成功,EOF - 操作失败(int)
测试程序:
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
cout<<"请输入一个字符串,它会放入缓冲区中"<<endl;
char c = getchar();
cout<<"用 getchar() 从缓冲区中刚刚取出来的字符:"<<c<<endl;
cout<<"将字符放回缓冲区"<<endl;
ungetc(c,stdin);
cout<<"用 getchar() 从缓冲区中再次取出字符"<<endl;
c = getchar();
cout<<"刚刚取出的字符:"<<c<<endl;
return 0;
}
运行结果:
2015.4.28 printf("%*s%s%*s",______); 的使用
一道小题目:
1 #include <stdio.h>
2 const char str[6] = "hello";
3
4 int main()
5 {
6 printf("|");
7 printf("%*s%s%*s",__________);
8 printf("|\n");
9 return 0;
10 }
输出结果应该是:
那么问题来了,第7行的横线上应该填写什么呢?
答案:
3,"",str,3,""
2015.5.1 求二进制中1的个数
一个简便算法:
1 int Count(int n)
2 {
3 int count = 0;
4
5 while (n) {
6 n = n & (n-1);
7 count++;
8 }
9
10 return count;
11 }
2016.12.4 字符串的长度(strlen)
先看下面代码:
1 #include<stdio.h> 2 #include<string.h> 3 int main() 4 { 5 char s1[] = "\6789"; 6 char s2[] = "\789"; 7 char s3[] = "\89"; 8 printf("%d\n",strlen(s1)); 9 printf("%d\n",strlen(s2)); 10 printf("%d\n",strlen(s3)); 11 return 0; 12 }
思考它的输出结果。
……
思考结束了吗?
正确输出如下:
3 3 2
分析:
s1实际由三个字符组成:'\67','8','9'
s2实际由三个字符组成:'\7','8','9'
s3实际由两个字符组成:'\8','9'
对比他们的输出结果,会发现差别基本在第一个字符上,即转义字符,为什么会有这样的差别呢?因为'\'后如果出现了数字,则会取后面不同位数的数作为八进制进行转义。那么什么时候应该取多少位进行转义呢?
处理规则如下:
1、'\'默认会取后面的三个数字作为八进制数字进行字符转义;
2、如果'\'后第三个数字不是一个八进制数(例如>7的数字 ),则将其作为一个单独的字符;
3、如果'\'后第二个数字也不是八进制数,则也将其作为一个单独字符;
4、如果'\'后第一个数字就不是八进制数,则也将其作为一个单独字符,且转义之后的字符就是这个数字本身,例如s3中第一个字符其实就是字符'8','\8'=='8'。
由此可见,'\'会尽量取后面的三个数字作为八进制数字进行转义,如果取不到三位八进制数,则退而求其次,能取几位取几位,如果一位八进制数也取不到,则'\'后的符号转义之后就作为符号本身存在。
总结一下,'\'后遇到数字的转义处理优先级为:'\ooo' > '\oo' > '\o' > '\c'(符号本身)
Freecode : www.cnblogs.com/yym2013