jkm99的个人空间 https://www.eechina.com/space-uid-71395.html [收藏] [复制] [RSS]

博客

C语言<一>

已有 1977 次阅读2013-6-3 23:13 |个人分类:C语言| C语言

 printf("格式字符串", ...);
  %i/%d           int
  %f/%lf           float/double
  %hd/%ld       short int/long int
  %u                unsigned int
  %c                char
  %s                string
  %p                address
  %o               八进制
  %x/%X        十六进制
  %g               float/double去尾零
  %e/%E        科学计数法
   %%            %
 unsigned 无符号             格式:%u
 signed 有符号                格式:%d
 默认是有符号的,比如signed char ch;可以直接写成: char ch;
数据类型:
 int
 signed int ,有符号数最高位为符号位,0代表正数,1代表负数
 最大的正数:01111111 11111111 11111111 11111111
 最小的负数:10000000 00000000 00000000 00000000 ,负数以补码的形式存储 
 unsigned int
 最大数: 11111111 11111111 11111111 11111111 , 最大的数加1就变为最小的数了
 最小数: 00000000 00000000 00000000 00000000 , 最小的数减去1就变为最大的数了
 32位操作系统:4字节,32位
 16位操作系统中:2字节,16位

 short int 短整型 格式:%hd
 2字节,16位
 无符号短整型 unsigned short int 格式:%hu
 long int    格式:%ld
 long long int 格式:%lld
 unsigned long long int 格式:%llu
 凡是int前面有修饰的类型 int可以省略不写, 如:unsigned int 可写成:unsigned
 不能在float或double前加unsigned或signed
 printf("%7.2f\n", f);//f总宽度是7,保留两位小数
 C提供三种浮点类型
  Float:单精度
  Double:双精度
  Long  double :扩展双精度
 C标准没有说明精度的范围有多少
 IEEE提供了精度:
  Float 1.17548*10(-38)~3.40282*10(38)
  Double 2.22507*10(-308)~1.79769*10(308)
 浮点常量
 以下浮点常量有效
  57.0  57.  57.0e0  57E0  5.7e1 5.7e+1  .57e2 570e-1
 整数常量(字面值)
 3被认为是int
 3.5被认为是double
 3.5f被认为是float
 3.5L被认为是long double
 35L被认为是long int
 35LL被认为是long long
 35u被认为是unsigned int
 35UL是unsigned long
 八进制和十六进制
 0377
 0x12ab
 补码=反码+1
=========================================
 sizeof(类型)  
 sizeof(变量名)  
 sizeof(表达式)
 sizeof只关心类型,只会分析括号中的类型,不会对括号中的内容进行运算。如:
  int i = 5;
  sizeof(i=10)=4;
   sizeof(i+3.14)=8;//3.14是double类型
 + - *  /  %
 运算符/可能产生意外 的结果
 运算符%要求操作数是整数
 把0做为/或%的右操作数会出现未定义的行为
 当运算符/和%用于操作负数,其结果未定义
 C89中,操作数的其中之一是负数,结果可以向上取整,也可以向下取整。如-9/7的结果可以是-1,也可以是-2。
  如果i和j其中一个是负数,i%j的结果依赖具体实现
 C99中, 除法的结果总是向零截取,因此 -9/7的结果是-1,i%j的结果符号与i相同。
/**************************************************************************/
 取余%
 被除数为正数,余数为正数
 被除数为负数,余数为负数
 5 % -3 = 2
 -5% -3 = 2
 -5% 3  = -2
/**************************************************************************/
 数组名之间不能赋值
 数组名传递给函数时传递的是一个地址

 数组作为参数时我们一般传递两个参数,数组名(数组首地址)和数组长度
 void print(int x[], int n){
       int i = n;
       while(n--){
           printf("%d\t", x[i-n-1]);
       }
      printf("\n");
 }
 //二维数组定义
 void two_dimension_print(int x[][LINE], int len)
 {
  ... ...
 }
 ... ...
 int array[2][4]={0,0};
 two_dimension_print(array, 4);
... ...

函数存在隐式声明,它的返回值为int类型, 何为隐式声明,即不管你是什么类型它都指定为int类型
C99规则:
 在调用一个函数之前,必须对其进行定义或声明
 
 
 形式参数和实际参数的区别
  void形参和空形参
  函数调用 中的值传递
  实际参数的转换
  编译器在调用前遇到原型
  编译器在调用前没有遇到原型
  float --> double
  char,short --> int
 数组型参数
 形式参数可以不用说明数组的长度
 函数中无法确定数组长度,只能用第二个参数传入
 形参是多维数组时,可以不指定数组的长度,但一定要指定数组的列数。
 #include <stdlib.h>
 void exit(int state);
 exit(0);//退出整个函数
 main函数中的rerurn与exit都是退出整个函数
 
scanf函数小技巧: 
 scanf("%*[^\n]");scanf("%*c");//这两个语句的作用是清空缓冲区。
 
局部变量
 作用域:函数内部或者更小
 生命周期:函数调用期间,函数执行时开始分配,函数调用结束时自动释放
 局部优先:局部变量优先于全局变量(当两者重叠时),如:
 ... ...
 int x=10;
 void fa(int x)
 {
  printf("in fa x=%d\n", x);//打印的是局部变量x的值
  int i=0;
  for(; i<10; i++){
   int x = i;
   printf("in for(): x = %d", x);//打印的是此语句上定义的x的值
 }
 
 int main(){
  fa(10);
  return 0;
 }
静态变量
 作用域:函数内部或者更小
 声明周期:整个函数运行期间,不受函数的限制
  
/**************************************************************************/
//函数返回指针的问题
 ... ...
 ... ...
int *fa(int *x){
     (*x)++;
     printf("in fa:x = %p\n", x);
     return x;    //ok
}
int *fb(void){
     int x = 100;
     printf("in fb:&x = %p\n", &x);
     return &x; //不要返回局部变量的地址,函数返回时局部变量已经释放
}
int *fc(void){
    static int si = 100;
    return &si; //返回静态局部变量的地址是安全的

int main(void)

 int a = 30;
 int b = 10;
 int *pa = fa(&a);
 printf("pa = %p\n", pa);
 
 int *pb = fb();
 printf("pb = %p\n", pb);
 int *pc = fc();
 printf("pc = %p\n", pc);
 printf("*pc = %d\n", *pc);
 printf("\n");
 return 0;
}
运行结果: 
[root@localhost workspace]# ./pointer
in fa:x = 0xbffccbd4
pa = 0xbffccbd4
in fb:&x = 0xbffccba4
pb = 0xbffccba4
in fc:&si = 0x8049974
pc = 0x8049974
*pc = 100
//=============================================================
一个指针永远占4字节
sizeof(p) == 4;//p为指针
指针相减:(pointer1 - pointer)/sizeof(指针类型)
int x;
int* p1 = &x;
int* p2 = p1 +6;
p2 - p1 = 6;//两个指针相减并不是把它们的地址数值上的值相减
数组:int a[10] = {1,2,3,4,5}
在数值上:&a = a = &a[0]
但是不能:int *p = &a; //error
a[i] = *(a+i) = *(i+a) = i[a]
数组名的值是不可改变的:a++; //error,数组名是一个常指针
数组越界可能段错误,可能什么事都没有,可能破坏其他的数据
 
//==================================================================
字符串要点:
  printf("%p\n", "abcdefg"); //打印的是存放该字符串的首地址
  char c = "abcdefg"[1];//"abcdefg"返回该字符串的首地址
  printf("c = %c", c); //c = 'b'
 "abcedefg"[0] = 'A'; //error, 存放在代码区,字符串字面值不可修改
 
数组在栈区保存,字符串保存在代码区, 代码区是只读的
不可给数组名赋值
 char str[]="aaa"; //字符串保存在栈区
 str = "AAA"; // error, 数组名是常量,不能被修改,数组名不能出现在 '=' 左边
 char *str2 = str; //ok
 str[0] = 'A'; //ok
 str = "abcdefg"; //ok
 str[0] = 'A'; //error
 
 字符串面量值保存在代码区,代码区只读,数组保存在栈区,可修改
 一个指向字符串的指针能不能被修改,是看它指向的是代码区还是栈区,如果是栈区可修改,若是代码区则不能
//=========================================== 
 scanf读不进空格,如:
 ... ...
 char str[20];
 scanf("%s", str);
 printf("%s\n", str);
... ...
 输入:abcdef ghig
 输出:abcdef //原因是scanf读不进空格
 
 printf("%10.6s\n", str);//打印字符串前面6个字符,字符串宽度为10,因为只打印前面6个字符,所以前面会补4个空格
 
输入
  scanf(“%s”, str);//注意不需要加&
  scanf永远不会读入空白符,而会跳过,换行、空格、制表等空白符会使scanf结束
  gets()可以读取一行,而且不会在开始读字符之前跳过空白
  gets()会持续读入直到换行符停止
  gets()会忽略掉换行符
 
//=============================================
 ... ...
 //以下代码存有风险
 char *str3; //野指针
 scanf("%s", str3);//有可能破坏数据,有可能段错误,有可能什么事都没有
 printf("%s\n", str3);

/*************************************************/
/*************************************************/
    const在指针上的用法
/*************************************************/
  ... ...
 int a = 10;
 const int *pa = &a; //pa所指向的空间不可以通过pa进行修改
 //*pa = 30; //error
//======================================= 
 int b = 20;
 int* const pb = &b;//pb本身的值不可被修改
 //pb = &a; //error
 *pb = 200;//pb所指向的空间可以被修改
//====================================== 
 int c = 12;
 const int* const pc = &c;  //pc所指向的空间以及pc本身的值都不可被改变
 //pc = &b; //error
 //*pc = 300; //error
//======================================
 const char *str1 = "abcdefg";
 //str1[0] = 'A'; //error
 str1 = "ABCDEFG";//ok
 char* const str2 = "abcdef";
 //str2 = "ABCDEF";//编译错误
 //str2[0] = 'A';//段错误

 const char* const str3 = "abcdef";
 //str3 = "ABCDEF";//编译错误
 //str3[0] = 'A'; //编译错误

 char str[] = "abcdefg";
 const char *str4 = str;
 //str4[0] = 'A'; //编译错误
 str4 = "ABCED"; //ok
 
 char* const str5 = str;
 str5[0] = 'A'; //ok
 //str5 = "ABCDEF"; //error 编译错误

//字符串
 char str[10] = "abcdefg";
 strcpy(str, "abcdefghigklmalkdf", 10); //这是有问题的,因为'\0'无处放,所以当打印str时字符串后面可能出现乱七八糟的东西
 strcpy(str, "abcdefghigklmalkdf", 9); //ok了
 strlen(str);//不包括'\0'
 
 char *ss[3] = {"aaaaa", "bbbfb", "ccccc"};//字符串存放在代码区
 ss[0] = "AAAA";//OK
 
/*********************************************************************************
**********************************************************************************
*********************************************************************************/
宏定义:
 不要在调用宏函数时传带 ++, --的参数
 括起整个表达式,以防止宏函数参与运算时出现问题
 括号括起变量,以防止传入参数时表达式出现问题
__LINE__             被编译文件行号
__FILE__  被编译文件名
__DATE__ 编译的日期
__TIME__  编译的时间
__STDC__ 如果编译器是标准的,那么值为1
 
#运算符
 只能出现在宏函数中,其作用是将参数字符串化
 #define PTINT_INT(n) printf(#n “=%d\n”, n);
 ##运算符
  将两个记号“粘合”在一起,成为一个记号,其中一个记号一般为宏参数
#define ID(n) i##n
int ID(1), ID(2), ID(3)
#define GEN_MAC(type) \
 type type##_max(type x, type y) \
 { return x > y ? x : y;}

#ifdef IA32 等效于 #if defined (IA32)
#undef IA32  //#undef 是取消宏定义
 
结构体:
struct{
 int id;
 char name[10];
 int onHand;
}part1,
part2 = {1, "part2", 100},
part3;
part1.id = 1;
strcpy(part1.name, "part1");
part1.onHand = 200;
part3 = part2;//这种赋值方式 ok
 typedef struct Part Part;//起别名

 int a[10];
 typedef int IA10[10]; //起别名
 IA10 b;
 int i;
 for(i=0; i<10; i++){
  printf("%d\t", b[i]); 
 }
 printf("\n");
 
/******************************************************************************/
结构的对齐与补齐:
 由于内存分配会将结构中的变量分配到内存的边界上,以方便访问。
 所以每个成员放的位置是从本身长度的倍数位开始放。但本身长度
 超过4时,以4计。此称为对齐。
 char   1倍
 short  2倍
 int    4倍
 double 4倍  
 整个结构变量的长度要保持内部最长成员(超过4以4计)的倍数。如果不够,则补齐。
 typedef struct Inner{
  short s;
  int  i;
 }Inner;
 //ssXXiiii, 补齐
 
 typedef struct Date{
  char c;
  short s;
  int i;
 }Date;
 //cxssiiii, 对齐
 
 typedef struct Date5{
  int i;
  char c;
 }Date5;
 //IIIIcxxx,补齐
 typedef struct Date6{
  double d;
  char c;
 }Date6;
 //DDDDDDDDCxxx,补齐
 typedef struct{
  char a;
  char b;
  char c;
 }Date7;
 //ccc
 
/******************************************************************************/
用整个一个字节(char)去表示一个二进制变量(如一个on/off开关)看起来有点铺张浪费,
而char已经是c中的可以独立分配与寻址的最小单位了。此时可使用域
MS-DOS操作系统中存储日期的方式
 struct file_date{
  unsigned int day : 5;
  unsigned int month:4;
  unsigned int year : 7;
 };
位域类型必须是int ,unsigned int或signed int,int 有些编译器上会有二义性。
不能取得域的地址。除此之外,域完全可以像其他变量一样使用。
int main(void)
{
 typedef unsigned int UINT;
 struct Ctl{
  UINT INT : 1;
  UINT C1 : 1;
  UINT C2 : 1;
  UINT C3 : 1;
  UINT RES : 1;
 }c;
 c.INT = 0;
 c.C1 = 1;
 c.C2 = 1;
 c.C3 = 0;
 //c.RES = 2; //溢出
 c.RES = 0;
 //&c.C1; //不允许取地址
 printf("sizeof(struct Ctl) = %d\n", sizeof(struct Ctl));//输出4
 printf("\n");
 return 0;
}

 

路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 立即注册

关于我们  -  服务条款  -  使用指南  -  站点地图  -  友情链接  -  联系我们
电子工程网 © 版权所有   京ICP备16069177号 | 京公网安备11010502021702
返回顶部