说明
不严格区分C与C++,反正就是C/C++的未明未知易错易忘点的总结。说实话,水平确实很低,感觉有时候敲代码经常要查阅网络资源,比如一些字符串的使用啊,还有类似string转int的方法,这些虽然在其他语言中可能就是System.In32.Parse(string1)就搞定了,可是在C语言中可能就特别麻烦。写这篇文章就是为了解决大部分这种经常遇到的问题。不过感觉好像也知识涉及了一小小部分的东西,博大精深的C语言啊,请受小弟一拜!不断更新中,有空就更新。
一:局部变量与全局变量
#include<iostream>
using namespace std;
int main()
{
int a = 1;
for(int i = 0; i < 3; i++)
{ int a = 2;
a+=i;
cout<<a<<" ";
}
cout<<a<<endl;
}
/*如果for中是 int a = 2;则输出为2 3 4 1;
如果for中是 a = 2,则输出 2 3 4 4;
如果for中没有a=2,则为 1 2 4 4;
可见:
只有局部函数中声明(指定类型)新的变量,且该局部变量名与全局变量名相同,才是特殊情况!
在局部函数中对该变量的操作并不会影响到
与其同名的全局变量。
一句话:
当且仅当局部函数中声明与全局变量同名的变量,则全局变量与其同名的局部变量相互独立,互不影响。
其他情况皆是局部函数在全局变量的统治下!
*/
二 数据输入
1.对于整数:% 位数控制 格式控制
如:%md表示:若长度小于m,则补空格,否则按实际成都输出。
特殊:%0md:位数不足m补0,而非不空格。
记忆:对于位数不足,补空格很好记忆,但如果位数超过m,是按实际长度输出的!并不会按m位输出, 那样岂不是失真了。。”不失真的重要性远高于位数控制“!
2.对于小数,显然就有保留几位的问题了!
%m.nf 总位数为m(包括小数点),n位小数,右对齐。
注意:m和整数表示的那个m相同,都是表示总的位数并不是整数位数、
3.可以利用有无"-"来控制左右对齐
如: %-ms”左对齐,不足时补空格
%0.m.ns:输出占m个字符位置,其中字符最多是m个,左补空格(这是输出字符串啊,不可能补‘0’吧。。)
4.其他
%o: 八进制输出
%x: 十六进制输出
三 数据输入
1.scanf()
scanf("%d%d%d",&a,&b,&c); a,b,c这三个数输入时,两个数据之间可以用一个空格或多个空格 ,tab键,回车键分隔。
也可以写成 scanf("%d,%d,%d",&a,&b,&c); 输入时用","分隔数据。
2.getchar()
将键盘输入的任何信息做为字符串处理,
c = getchar();
putchar(c);
举例:
char input;
while((input =getchar())!=‘ ‘&&(input!=‘\n‘))
{
num[count] = input;
count++;
}
或是
char input;
while((input =getchar())!=‘\n‘)
{
if(input!=‘ ‘)
{
num[count] = input;
count++;
}
else break;
}
上面的代码都能让输入的字符以空格或是换行符结束。
三 对static的一些补充
1 void fun() 2 { 3 int a = 1; 4 static int b = 1; 5 a++; 6 b++; 7 cout<<"a="<<a<<","<<"b="<<b<<endl; 8 9 } 10 int main() 11 { 12 for(int i = 0; i < 3; i++) 13 { 14 fun(); 15 } 16 } 17
输出 a=2,b=2
a=2,b=3
a=2,b=4
2.一般来说,函数不是文件作用域,可以再文件A中调用文件B中的函数,如果加上static,则只能在本文件中调用。
对应的是extern,表示函数可以再本文件中调用又可以在外部文件中调用。extern可以省略。另外在外部文件中调用时要先声明后调用。
四 字符数组
1.注意字符串是用字符数组存放的。
char c[5]={"abcde"}是错的。
因为C语言的编译系统会自动在最后一个字符后面增加一个结束标志‘\0‘,所以必须改为char c[6] 或是 char []。
char c[6]={‘a‘,‘b‘,‘c‘,‘d‘,‘e‘,‘\0‘}和char c[6]="abcde"是等价的。由此可见字符串和字符数组本质上并无区别,只不过字符串额末尾一定会有‘\0‘,字符串等价为其各元素单独相应放在字符数组中,并且在末尾加上一个‘\0‘。
2.字符串处理函数
首先C是面向过程的,故不会出现“对象.函数”的形式,只会有“函数(对象1,...)",返回空或其他值。
2.1 gets(字符数组名)
1 int main() 2 { 3 char a[100]; 4 gets(a); 5 cout<<a; 6 }
一次只能输入一个字符串,允许包含空格,而scanf()不允许。
2.2 strcat(str1,str2) 连接str2和str3 // catenate连接
1 int main() 2 { 3 char a[20]="asdf"; 4 char b[6]="ascsa"; 5 strcat(a,b); 6 cout<<a; 7 }
其中a应定义的足够大,以便连接字符串。这种方法等价于C++的”+“,在C++中可以直接str3 = str1+str2;两种方式都会删掉str1末尾的‘\0‘,然后与str2连接,当然str2的‘\0\会保留。
2.3 strcpy(str1,str2) //string copy
str1的长度也不能少于str2;
2.4 strcmp(str1,str2) //string compare
从第一位开始往后按ASCII码的大小进行比较,与字符串的长度无必然关系。C++中可以直接用">","<","!="等进行比较
2.5 strlen(str)
返回字符串实际长度,不包括‘\0‘;
2.6 strstr(str1,str2)
判断str2是否为str1的子串
2.8 字符数组做参数
注意:实际上,字符数组做为参数时,传送的是数组/字符串的首地址,定义形参时可以省略大小,大小由相应的实参字符串来确定,当读到‘\0‘时,就默认之前为整个数组/字符串
五 指针
1. 二维数组的指针表示
如:int a[3][4]可以分为3行一维数组。这3行数组的首地址分别为 a[0],a[1],a[2]
显然有:*a = a[0]=&a0][0]; *a+1 = a[0]+1 =&a[0][1]
类似的还有: *(a+i)+j = a[i]+j=&a[i][j]
**a = *a[0]=a[0][0]
*(*a+i) = *(a[0]+i) =a[0][i]
*(*(a+i)+j) = *(a[i]+j) = a[i][j]
总结:二维数组的指针表示数组元素有2个*,否则只有一个表示的是元素的地址、
*的右边必须直接跟"(",若没有则不改变结构的添上"( )",秉承 *(a+i)=a[i]的原则即可
如:**(a+i) = *a[i] = *(a[i]+0)=a[i][0]
*(*a+i) = *(*(a+0)+i)=*(a[0]+i)=a[0][i]
2. 指针作为函数返回值
1 int *fun() 2 { 3 .. 4 return &a 5 }
2. 函数指针
一个函数所包含的指令序列在内存中总是占用一段连续的空间,这段空间的首地址就是函数的入口,函数名就是这一地址。
定义: Type (*p)()
1 int (*pmax)() 2 pmax = max; //max为已定义好的函数 3 调用:z = (*pmax)(x,y);
函数指针变量调用函数和直接通过函数名调用函数的方式是不一样的,前者是间接访问,后者是直接访问。
六 C语言的内存动态分配
1.malloc
原型: void *malloc(unsigned int size)
函数返回的是申请空间的首地址的指针,类型为void,即不规定只想任何具体的类型,我们要用强制转换来使该空间能被指定类型的变量存储。
1 int *p; 2 p = (int*)malloc(sizeof(int)*100);
申请了能存储100个int(每个int有4个字节)的空间,即400个字节,返回一个指向int型变量的指针。
2. realloc
void realloc(void *p,unsigned int size)
1 char *p; 2 p = (char *)malloc(100); 3 p = (char*)realloc(p,256);
3. free()
释放动态申请的空间
1 char *p; 2 p = (char *)malloc(100); 3 free(p);
以上3个函数都在stdlib.h库中
4.void类型指针
void类型指针只表示一个抽象的类型的数据。,仅提供一个纯地址,而不指向任何对象。
1 int main() 2 { 3 int a= 10; 4 void* p; 5 p = &a; 6 cout<<p<<endl; 7 cout<<*p; //出错,‘void*‘ is not a pointer-to-object type 8 }
5. 动态数组
int n = 10;
int a[n]; //编译错误
静态数组大小必须是常量表示,不能使用变量或是函数表示大小,那怎么解决呢?
使用动态数组!静态数组空间可以通过变量名和下标配合使用,也可以通过指针变量使用。而动态数组只能通过指针变量来使用。
int n= 10;
int *a;
a = (int*)malloc(n*sizeof(int));
七 其他一些小东西
1. 结构体
常用型:
struct Student
{
...
}
Student st1,st2;
其他型
struct Student
{
...
}Struct Student st1,st2;
如果}后面直接接st1,st2,则不能在其他地方定义该结构体的变量。
2. 枚举
enum day{sun = 7, mon =1,tue,wed,thur,fri,sat}
未显示赋值的变量按”后一个是前一个值加1的规律"赋值。