C语言小结

来源:互联网 发布:翻译英语的软件 编辑:程序博客网 时间:2024/05/17 23:57
1)-lm 连接math.h类的函数库。如 gcc 3.c -o 3 -lm...2)EOF 的ASCII为-1,这是一个宏定义,而且必须为大写字母。和‘EOF’不一样,这是一个字符。3)其实int, char 除了占的字节数不同,其他没什么区别,可以这样理解。%d输出十进制,%c输出字符(只能输出一个字符,最低位的),而且,一个字母必须占一个字节。如 char i= 'NUL';相当于char i='L'(最低位);4)有符号的整数才有原码、反码和补码之分!其他的类型一概没有。二进制:0000 0000共8位; 可以表示2^8个不同的数; 这些数:0 -- 2^8-1 (无符号),-128-127(-2^7--2^7-1)有符号char型而最大的位数为2^(8-1)即2^7;依次为1*2^7 + 1*2^6 + 1*2^5 + 1*2^4 + 1*2^3 + 1*2^2 + 1*2^1 + 1*2^0;
 负整数在计算机中是以补码形式储存的,如计算机中为: 1000 0000--1000 0000--1111 1111--0000 0000--0000 0001--01111 1111从00000001到01111111依次表示1到127;    10000000在计算机中表示最小的负整数,就是这里的-128;   从10000001到11111111依次表示-127到-1;(补码的形式)总结一下,计算机储存有符号的整数时,是用该整数的补码进行储存的,0的原码、补码都是0,正数的原码、补码可以特殊理解为相同,负数的补码是它的反码加1。如:计算机中形式为10000110(补码)就表示十进制的-122 求其原码;十进制     原码  反码  补码122   0 1111010 01111010 01111010   -122  1 1111010 10000101 10000110(对于负数,最高位为1,不操作) 负数在计算机中的表示为:原码->反码->+1->补码;其中负数原码的求法为:最高位先置1,低位与负数的绝对值的原码相同。
5)如果数组S[N]   则s(是首项s[0]的地址)与&s(是整个数组的首地址)的地址是一样的 ;
6)char* f(int)        char str1[15];        char* str2=(char*)malloc(sizeof(char)*len);        char*str3=str2;  return str1,,不行   str1是局部变量,f结束时,str1所指的对象消失。  return str2,,行,,     str2消失,但是因为是malloc,所指向的对象不消失。  return str3,不行。     strcpy(str,"hello world")行 str="hello world"行
 char *p;   scanf("%s",p);这样是不行的。。p没有被分配内存 char a[10];scanf("%s",a); 行7)结构体:  typedef struct stu     char *name;   char add[20];   }Stu;     这里是类型Stu;  Stu s1;  s1.name=(char*)malloc(sizeof(char)*20);  s1.add  strcpy(s1.add,"hello,world"); 结构体地址,,&s1...; 成员地址顺序存放。 结构体赋值,s2=s1,所有的成员都相等。
 Stu *sp=(Stu*)malloc(sizeof(Stu) );指针结构体。 结构体的地址,是第一个成员的地址。
 但是,在struct中不可以 static int m; 不能变相的赋值为0; Stu class[2]={1,2,3,4}; memset(&str, 0, sizeof(str));8)volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。volatile的变量被解释成“直接存取原始内存地址”比较合适;“易变”是因为外在因素引起的,象多线程,中断等,并不是因为用volatile修饰了的变量就是“易变”了。  volatile对应的变量可能在你的程序本身不知道的情况下发生改变  比如多线程的程序,共同访问的内存当中,多个程序都可以操纵这个变量  你自己的程序,是无法判定何时这个变量会发生变化  还比如,他和一个外部设备的某个状态对应,当外部设备发生操作的时候,通过驱动程序和中断事件,系统改变了这个变量的数值,而你的程序并不知道。用到volatile的地方如:  1). 并行设备的硬件寄存器(如:状态寄存器)  2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)  3). 多线程应用中被几个任务共享的变量
指针函数与函数指针
int *pfun(int, int);(指针函数)    由于“*”的优先级低于“()”的优先级,因而pfun首先和后面的“()”结合,也就意味着,pfun是一个函数。即:     int *(pfun(int, int));    接着再和前面的“*”结合,说明这个函数的返回值是一个指针。由于前面还有一个int,也就是说,pfun是一个返回值为整型指针的函数。   类似:int * a[N]           a先与[]结合->数组  然后再与*结合,说明数组的元素是int*类型
   int (*pfun)(int, int);(函数指针)    通过括号强行将pfun首先与“*”结合,也就意味着,pfun是一个指针,接着与后面的“()”结合,说明该指针指向的是一个函数,然后再与前面的int结合,也就是说,该函数的返回值是int。由此可见,pfun是一个指向返回值为int的函数的指针。
    虽然它们只一个括号的差别,但是表示的意义却截然不同。函数指针的本身是一个指针,指针指向的是一个函数。指针函数的本身是一个函数,其函数的返回值是一个指针。
 
void MyFun(int x);    //申明一个函数——参数为int,返回值为void。void (*FunP)(int );    //申明一个指针——指向一个参数为int,返回值为void的函数。
int main(int argc, char* argv[]){   MyFun(10);     //这是直接调用MyFun函数   FunP=&MyFun;  //将MyFun函数的地址赋给FunP变量   (*FunP)(20);    //这是通过函数指针变量FunP来调用MyFun函数的。  MyFun(10);     //这里是调用MyFun(10);函数   FunP=MyFun;  //将MyFun函数的地址赋给FunP变量   FunP(20);    //这是通过函数指针变量来调用MyFun函数的。   MyFun(10);     //这里是调用MyFun(10);函数   FunP=&MyFun;  //将MyFun函数的地址赋给FunP变量   FunP(20);    //这是通过函数指针变量来调用MyFun函数的。
   MyFun(10);     //这里是调用MyFun(10);函数   FunP=MyFun;  //将MyFun函数的地址赋给FunP变量   (*FunP)(20);    //这是通过函数指针变量来调用MyFun函数的。(*MyFun)(10);     //看,函数名MyFun也可以有这样的调用格式
}总结:1. 其实,MyFun的函数名与FunP函数指针都是一样的,即都是函数指针。MyFun函数名是一个函数指针常量,而FunP是一个函数数指针变量,这是它们的关系。2. 但函数名调用如果都得如(*MyFun)(10);这样,那书写与读起来都是不方便和不习惯的。所以C语言的设计者们才会设计成又可允许MyFun(10);这种形式地调用(这样方便多了并与数学中的函数形式一样,不是吗?)。3. 为统一起见,FunP函数指针变量也可以FunP(10)的形式来调用。4. 赋值时,即可FunP=&MyFun形式,也可FunP=MyFun。
 
typedef int* PINT;    //为int* 类型定义了一个PINT的别名
typedef void (*FunType)(int );   //这样只是定义一个函数指针类型FunType FunP;              //然后用FunType类型来申明全局FunP变量
给你一个实例:要求:我要设计一个CallMyFun函数,这个函数可以通过参数中的函数指针值不同来分别调用MyFun1、MyFun2、MyFun3这三个函数(注:这三个函数的定义格式应相同)。实现:代码如下://自行包含头文件void MyFun1(int x);  void MyFun2(int x);  void MyFun3(int x);  
typedef void (*FunType)(int ); //②. 定义一个函数指针类型FunType,与①函数类型一至
void CallMyFun(FunType fp,int x);
int main(int argc, char* argv[]){   CallMyFun(MyFun1,10);   //⑤. 通过CallMyFun函数分别调用三个不同的函数   CallMyFun(MyFun2,20);      CallMyFun(MyFun3,30);   }void CallMyFun(FunType fp,int x) //③. 参数fp的类型是FunType。{  fp(x);//④. 通过fp的指针执行传递进来的函数,注意fp所指的函数是有一个参数的}void MyFun1(int x) // ①. 这是个有一个参数的函数,以下两个函数也相同{   printf(“函数MyFun1中输出:%d\n”,x);}void MyFun2(int x)    printf(“函数MyFun2中输出:%d\n”,x);}void MyFun3(int x)    printf(“函数MyFun3中输出:%d\n”,x);}
 
 
 
 
1.register(关键词) 尽可能把变量存在cpu内部寄存器,而不是通过内存寻址,从而提高效率。
 寄存器:内存把数据传放在寄存器,然后转给cpu
2.static 静态全局变量:作用域仅限于被定义的文件中,其他文件即使使用extern声明也无法使用它(从定义之处开始到文件结束) 静态局部变量:仅限于函数里  静态变量存放在静态区。  静态函数:函数作用域仅限于本文件,所以又称为内部函数。好处是不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件的函数重名。3.sizeof()  int a[20][20]  sizeof(a)与sizeof(&a)是一样的,都是整个二维数组的大小,因为&a表示的是整个二维数组a整体的首地址, a表示的是第一行元素的首地址,所以&a+1与a+1,这个1代表的空间是不同的,&a+1 加的是整个二维数组的大小,a+1加的是整个第一行的大小。          int a[20] sizeof(a)与sizeof(&a)是一样的,都是整个一维数组的大小, a表示第一个元素的地址,&a表示整个一行的(即整个数组)的首地址,因为只有一行。所以,&a+1 与a+1 中,这个1代表的空间也是不同的,前者加的是整个一行的大小,后者加的是一个元素的大小。
4-switch case 后面只能是int,char,不能是浮点型,不能是字符串。 switch()  case 1:printf();break;  default:printf();break; }5.void* “空指针类型”,可以指向任意类型的数据。
 在ANSI标准,不能对void指针进行操作。  void*p;p++;就是错的  (char*)p+=1;是错的  (char*)p++;是可以的 而GUN则认为:void*的的算法与char*一样。
6.return    char*F(void)    char str[30];   .......   return str;  str[]是局部变量,位于栈内存,在F()结束时将被释放,所以返回它的首地址,将会导致错误。
7.const(关键词) 修饰后为:只读变量(具有不可变性),所以必须在定义的同时初始化。而且编译器不会为普通的const变量分配存储空间,而是将它们保存在符号表里。在程序运行的过程中只有一份拷贝。而define定义的宏常量,在内存中有若干个拷贝。
8.Sleep函数目录   功 能: 执行挂起一段时间   用 法: unsigned sleep(unsigned seconds);   在VC中使用带上头文件   #include <windows.h>   在gcc编译器中,使用的头文件因gcc版本的不同而不同   #include <unistd.h>
 注意:在VC中Sleep中的第一个英文字符为大写的"S" 在标准C中是sleep, 不要大写..  下面使用大写的来说明,, 具体用什么看你用什么编译器. 简单的说VC用Sleep, 别的一律使用sleep. Sleep函数的一般形式:   Sleep(unisgned long);  其中,Sleep()里面的单位,是以毫秒为单位,所以如果想让函数滞留1秒的话,应该是Sleep(1000); 在Linux下,sleep中的“s”不大写  sleep()里面的单位是秒,而不是毫秒。在内核中,sleep的实现是由pause函数和alarm函数两个实现的。例  #include <windows.h>  int main()  {   int a;   a=1000;   printf("你");   Sleep(a);      printf("好");         return 0;  }
9. 辗除法:  a%b=temp..... a->b;b->temp.....循环,直到b!=0;   最大公约数(起始的a*b)除上最后的a值。   最小公倍数:最后的a.10. 八皇后中的是“判断递归” 计算机的四则运算11. 负数===是以补码的形式表示----负数绝对值的反码加1 正数也是以补码的形式存储,正数的补码等于源码。
12. void main(int argc, char *argv[])  ... ... argc和argv是main函数的形式参数。这两个形式参数的类型是系统规定的。如果main函数要带参数,就是这两个类 型的参数;否则main函数就
 没有参数。变量名称argc和argv是常规的名称,当然也可以换成其他名称。
 (1) 可执行文件名称和所有参数的个数之和传递给argc; (2) 可执行文件名称(包括路径名称)作为一个字符串,首地址被赋给argv[0],参数1也作为一个字符串,首地址 被赋给argv[1],... ...依次类推。 例如,现在运行命令行(test是编译后的exe文件名称): C:\TC\test how are you 那么test工程的main函数参数argc=4; argv[0]将保存字符串"C:\TC\test"的首地址; argv[1]将保存字符串"how"的首地址; argv[2]将保存字符串"are"的首地址; argv[3]将保存字符串"you"的首地址;
13 int a[3][3] 
 *(*a)是二维数组的第零行的第一个元素。*(*(a+1))是二维数组的第一行的第一个元素。
 int a[2][2]={1,2,3,4}; printf("%p %p %p %p %p %p\n",a,*a,&a,a+1,*a+1,(&a+1));
 a代表二维数组第一行的首地址,相当于二维指针,a+1是加一行的空间。 *a代表的是每一个元素的地址,相当于一维指针,刚好这是第一个元素的地址。*a+1是加一个元素的空间。 &a代表的是整个数组的地址,相当于三维指针。&a+1加的是整个数组的空间。
 int a[2][2]={1,2,3,4};  结果依次为sizeof(a)=16 ,sizeof(&a)=16 ,sizeof(*a)=8 ,sizeof(a+1)=4   sizeof(*a+1)=4 ,sizeof((&a+1))=4 分析:1,只有首地址才可代表一个二维数组或一行       2,sizeof() 测得是变量类型的大小。           3,比如a+1,加的虽是一行的空间大小,但是sizeof(a)的大小却是整个数组的大小;*a+1,加的虽是一个元素的空间大小,但是sizeof(a)的大小却是整个一行的大小 如:a的类型是int**,这里得看指针的每一层所包含的空间大小,相当于一个二维指针,一层是2个元素的空 间,总共是2*2个元素的空间。
  *a的类型是int*类型,一层是2个元素的空间。
 &a的类型是int*(**),最内层的是一个二维数组的空间,即2*2个元素的空间,最外层是只用一个元 素的指针,所以是一个元素的空间,相当于一个三维数组,最外层只有一个元素空间(类似于只有1个a[0]),所以是1*2*2的空间。
16 double t=5/2  输出2.00000 double   t=5.0/2 输出2.5000
 int x=3; double t=x==4-1; 输出t为1.00000
17 int x=1; for,while,if语句中的是判断0和非0; if(x=2)括号内被赋值为为2,此时,if为真 if(x=0.5)括号内为0;即为假;     总结,在if()中,x被重新赋值,经过转化后,只要x不被赋值为0,就判断为真。反之,只要x被赋值为0,if判断即为假。
18 c="hello,world"; c="huanf";这样可以
 c="hello world"; 操作右边的常量,让它变化不行,c是变量可以重新赋值。 *c+1;是不允许的;