学习c语言

4.21

extern的使用

变量的声明有两种情况:
1、一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间。
2、另一种是不需要建立存储空间的,通过使用extern关键字声明变量名而不定义它。 例如:extern int a 其中变量 a 可以在别的文件中定义的。
除非有extern关键字,否则都是变量的定义。
extern int i; //声明,不是定义
int i; //声明,也是定义

函数外定义了一个变量后,在函数内赋值似乎可以不用extern?
可以这么理解,extern 是用来在另一个文件中声明一个全局变量或函数。(两个文件)

4.23

字符与字符串

char s='a';//定义字符
char s[]="abcd"定义字符串

注意单引号和双引号
%c输出字符,%s输出字符串。

解释以下代码的输出结果为什么是0:int c=100;printf(“%f\n”,c);
在这段代码中,变量c被赋值为100,但是在printf函数中使用了%f格式化符号,它会将c作为浮点数输出。由于c是一个整数类型的变量,因此在输出时会发生隐式类型转换,将c转换为浮点数类型。但是,由于浮点数和整数在内存中的表示方式不同,因此在将c转换为浮点数时,它的值会被解释为一个非常小的浮点数,这个浮点数的值接近于0,因此输出结果为0.000000。如果想要输出变量c的整数值,应该使用%d格式化符号,而不是%f格式化符号。

定义常量

好的编程习惯:定义常量名用大写字母

问:define 定义的是不带类型的常数,只进行简单的字符替换。在预编译的时候起作用,不存在类型检查。那在进行运算的时候,如何知道它是数值还是字符(串)?
答:无论它们是数值还是字符,都只是简单的文本替换,没有类型检查。在进行运算时,如果宏定义的值是数值类型,那么它们会被当作数值进行运算。如果宏定义的值是字符类型,那么它们会被当作字符进行处理。

注意:define 注意“边缘效应”,
例:

#define N 2+3;//N 的值是 5。
double a;
a = (float)N/(float)2;

在编译时我们预想 a=2.5,实际打印结果是 3.5 原因是在预处理阶段,编译器将 a=N/2 处理成 a=2+3/2,这就是 define 宏的边缘效应,所以我们应该写成 #define N (2+3)。

总结:所谓的预处理其实就是在编译前将源代码中相应的字符串单词替换成定义的另一个字符串单词。
比如:

#define PI 3.14159;
area = PI * r * r;

编译时预处理后为:

#define PI 3.1415926
area = 3.1415926 * r * r;

此时常量是不可能存储在内存中的。而 const 是作为修饰词对变量进行修饰,即为“只读”变量,是单独存储在内存中的。
#define 的声明 只是一个别名,并不会改变其内在逻辑,也就是不会自动加上小括号增加优先级。
可以理解为在预处理的时候,编译器将代码中的常量全换成了#define中所定义的内容,所以说要注意括号!又如:
求 a 的值:

#include <stdio.h>
#define SQR(x) x*x

int main()
{
   int a=16,k=2,m=1;
    a/=SQR(k+m)/SQR(k+m);
    printf("a=%d",a);
}

输出结果:a=2。是不是跟我们想象的结果不太一样?

c存储类之extern存储类

extern int x;
int main ()
{    
    x=8;
    printf("%d",x);
    return 0;
}

注意的是,因为x是一个外部变量,所以它的定义应该在其他文件中进行,这里只是声明一下。如果没有在其他文件中定义x,那么这段代码在链接时会出现链接错误:[Error] ld returned 1 exit status

c存储类之static存储类

在用static修饰局部变量后,该变量只在初次运行时进行初始化工作,且只进行一次。
如:

#include<stdio.h>  
void fun()  
{   
    static int a=1; a++;   
    printf("%d\n",a);  
}  
int main(void)  
{   
    fun();   
    fun();   
    return 0;  
}  

程序执行结果为: 2 3
说明在第二次调用fun()函数时,a的值为2,并且没有进行初始化赋值,直接进行自增运算,所以得到的结果为3.
对于静态局部变量如果没有进行初始化的话,对于整形变量系统会自动对其赋值为0,对于字符数组,会自动赋值为’\0’.

extern是整个工程可见,而static是本源文件可见
但是,static定义的变量只能在当前 c 程序文件中使用,在另一个 c 代码里面 , 即使使用 extern 关键词也不能访问这个static变量。如果实在函数内部定义的,那么这个变量只初始化一次,即使再次调用这个函数,这个static变量也不会再次初始化 , 这个变量的取值就会一直保存着,也就是说,当你再次调用这个函数的时候,里面用到这个static变量时,就会发现,它还是上一次函数调用时的结果(注意是结果,而不是初始值!所以说,要尤其注意在循环语句中的函数里定义static变量,循环后它会保留上一次循环的结果,而不会在第一次以后调用函数时再次初始化它)。

4.24

c运算符

a++ 与 ++a 的区别,先赋值后运算:c = a++。先运算后赋值:c = ++a。
按位与&:都是1才是1,否则就是0
按位或|:都是0才是0,否则就是1
按异或^:相同是0,相异是1
利用异或 ^ 来交换两个数的值,而且不引入其他变量:a=ab;b=ab;a=ab;仅用一行代码实现的方法:a=b=a=b;
利用位与 & 运算,判断一个整数是否是2的整数次幂。
取余,余数可以是正数也可以是负数,由 % 左边的整数决定:如果 % 左边是正数,那么余数也是正数;如果 % 左边是负数,那么余数也是负数;

运算符优先级:
括号成员是老大; // 括号运算符 成员运算符. ->
全体单目排老二; // 所有的单目运算符比如++、 --、 +(正)、 -(负) 、指针运算*、&
乘除余三,加减四; // 这个"余"是指取余运算即%
移位五,关系六; // 移位运算符:<< >> ,关系:> < >= <= 等
等与不等排行七; // 即 == 和 !=
位与异或和位或; // 这几个都是位运算: 位与(&)异或(^)位或(|)
"三分天下"八九十;
逻辑与,逻辑或; // 逻辑运算符: || 和 &&
十一十二紧挨着; // 注意顺序: 优先级(||) 底于 优先级(&&)
条件只比赋值高, // 三目运算符优先级排到 13 位只比赋值运算符和 “,” 高
逗号运算最低级! //逗号运算符优先级最低

一句话系列:
逻辑是将两个操作值转换成Boolean进行操作。
逻辑与:双真真(双真为真,下同);
逻辑或:单真真;
逻辑非:取反;
没有说明的情况都为假(0)。
按位是将两个操作值转换成二进制然后逐位进行操作。
按位与:双真真;
按位或:有真真(有一个真即为真,两个真的情况也属于有一个真);
按位异或:单真真(区别于有真真,两个真的情况不属于单真);
按位是二进制逐位操作,未说明的皆假。

c语言中运算符优先级的总结:
初等运算符>单目运算符>算术运算符>关系运算符>逻辑运算符>条件运算符>赋值运算符
初等运算符有:()、[ ]、->、. (后两者均为结构体成员运算符);
单目运算符有:!、~、++、–、sizeof、&、
算术运算符有:
、/、+、-、<<、>>;
关系运算符有:<、<=、>、>=、==、!=、&、^、|;(此栏排列仍有优先级顺序哦);
逻辑运算符有:&&、||;
条件运算符有:?:(即三目运算符);
赋值运算符有:=、+=、-=、*=、/=、%=、>>=、<<=;等
另外,单目运算符的优先级都高于双目运算符。

c判断

if语句,括号内是一个布尔表达式
if…else语句,一个 if 语句 后可跟一个可选的 else 语句,else 语句在布尔表达式为假时执行。
嵌套if语句,可以在一个 if 或 else if 语句内使用另一个 if 或 else if 语句。
switch语句,注意若不在case后面加break,则会将满足条件的case后面的所有case的语句跑一遍。
嵌套switch语句

?:运算符(三元运算符)
a?b:c 若a真,则b,否则c

5.16

c循环

while循环

for循环

C 语言中 for 循环的语法:

for ( init; condition; increment )
{
   statement(s);
}

init 会首先被执行,且只会执行一次。这一步允许您声明并初始化任何循环控制变量。您也可以不在这里写任何语句,只要有一个分号出现即可。接下来,会判断 condition。如果为真,则执行循环主体。如果为假,则不执行循环主体,且控制流会跳转到紧接着 for 循环的下一条语句。在执行完 for 循环主体后,控制流会跳回上面的 increment 语句。该语句允许您更新循环控制变量。该语句可以留空,只要在条件后有一个分号出现即可。条件再次被判断。如果为真,则执行循环,这个过程会不断重复(循环主体,然后增加步值,再然后重新判断条件)。在条件变为假时,for 循环终止。

do…while 循环

C 语言中 do…while 循环的语法:

do
{
   statement(s);

}while( condition );

请注意,条件表达式出现在循环的尾部,所以循环中的 statement(s) 会在条件被测试之前至少执行一次。如果条件为真,控制流会跳转回上面的 do,然后重新执行循环中的 statement(s)。这个过程会不断重复,直到给定条件变为假为止。

琢磨while与dowhile的区别

嵌套循环

待学。。。

break语句

C 语言中 break 语句有以下两种用法:当 break 语句出现在一个循环内时,循环会立即终止,且程序流将继续执行紧接着循环的下一条语句;它可用于终止 switch 语句中的一个 case。循环内多用if来执行break:

while( a < 20 )
   {
      printf("a 的值: %d\n", a);
      a++;
      if( a > 15)
      {
         /* 使用 break 语句终止循环 */
          break;
      }
   }/*起到15<a<20条件的作用*/

continue语句

C 语言中的 continue 语句有点像 break 语句。但它不是强制终止,continue 会跳过当前循环中的代码,强迫开始下一次循环。对于 for 循环,continue 语句执行后自增语句仍然会执行。对于 while 和 do…while 循环,continue 语句重新执行条件判断语句。

do中continue,会跳出来执行下面的while。用于跳过一连串输出值中的某一个

/* 局部变量定义 */
   int a = 10;

   /* do 循环执行 */
   do
   {
      if( a == 15)
      {
         /* 跳过迭代 */
         a = a + 1;
         continue;
      }
      printf("a 的值: %d\n", a);
      a++;
     
   }while( a < 20 );
   /*这样就不会输出15了*/

goto语句

C 语言中的 goto 语句允许把控制无条件转移到同一函数内的被标记的语句。注意:在任何编程语言中,都不建议使用 goto 语句。因为它使得程序的控制流难以跟踪,使程序难以理解和难以修改。任何使用 goto 语句的程序可以改写成不需要使用 goto 语句的写法。

goto label;
..
.
label: statement;
/*在这里,label 可以是任何除 C 关键字以外的纯文本,
它可以设置在 C 程序中 goto 语句的前面或者后面。*/
/* 局部变量定义 */
   int a = 10;
 
   /* do 循环执行 */
   LOOP:do
   {
      if( a == 15)
      {
         /* 跳过迭代 */
         a = a + 1;
         goto LOOP;
      }
      printf("a 的值: %d\n", a);
      a++;
     
   }while( a < 20 );
    /*这样就不会输出15了*/

无线循环

常用语句:for(;;),注意:您可以按 Ctrl + C 键终止一个无限循环。

一些习题

使用 while, for 分别输 1~100 以内的所有的奇数和偶数的和
用 do while 求算术平方根
求100以内的素数
用 continue 语句求输出 100~200 之间的不能被3整除的数

c函数

函数声明告诉编译器函数的名称、返回类型和参数。函数定义提供了函数的实际主体。函数还有很多叫法,比如方法、子例程或程序,等等。

定义函数

C 语言中的函数定义的一般形式如下:

return_type function_name( parameter list )
{
   body of the function
}

在 C 语言中,函数由一个函数头和一个函数主体组成。下面列出一个函数的所有组成部分:
返回类型:一个函数可以返回一个值。return_type 是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type 是关键字 void。
函数名称:这是函数的实际名称。函数名和参数列表一起构成了函数签名。
参数:参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
函数主体:函数主体包含一组定义函数执行任务的语句。

函数声明

在函数声明中,参数的名称并不重要,只有参数的类型是必需的,因此下面也是有效的声明:

int max(int, int);

当您在一个源文件中定义函数且在另一个文件中调用函数时,函数声明是必需的。在这种情况下,您应该在调用函数的文件顶部声明函数。

调用函数

调用函数时,传递所需参数,如果函数返回一个值,则可以存储返回值。例如:

 /* 局部变量定义 */
   int a = 100;
   int b = 200;
   int ret;
 
   /* 调用函数来获取最大值 */
   ret = max(a, b);
 
   printf( "Max value is : %d\n", ret );

由于程序是从上向下执行,所以函数要先声明,后调用。这种先后是文档中所处位置的先后,不是时间的先后。如果函数非要写在主函数之后可以在主函数之前加入一个函数的前置声明(写一下函数的声明式即可)。

函数参数

如果函数要使用参数,则必须声明接受参数值的变量。这些变量称为函数的形式参数。形式参数就像函数内的其他局部变量,在进入函数时被创建,退出函数时被销毁。当调用函数时,有两种向函数传递参数的方式:

传值调用

该方法把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数不会影响实际参数。默认情况下,C 使用传值调用来传递参数。一般来说,这意味着函数内的代码不能改变用于调用函数的实际参数。

引用调用

通过指针传递方式,形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。传递指针可以让多个函数访问指针所引用的对象,而不用把对象声明为全局可访问。

补充

内部函数

如果一个函数只能被本文件中其他函数所调用,它称为内部函数。在定义内部函数时,在函数名和函数类型的前面加 static。内部函数又称静态函数。使用内部函数,可以使函数的作用域只局限于所在文件。即使在不同的文件中有同名的内部函数,也互不干扰。提高了程序的可靠性。

外部函数

如果在定义函数时,在函数的首部的最左端加关键字 extern,则此函数是外部函数,可供其它文件调用。C 语言规定,如果在定义函数时省略 extern,则默认为外部函数。在需要调用此函数的其他文件中,需要对此函数作声明(不要忘记,即使在本文件中调用一个函数,也要用函数原型来声明)。在对此函数作声明时,要加关键字 extern,表示该函数是在其他文件中定义的外部函数。

内联函数

内联函数是指用inline关键字修饰的函数。在类内定义的函数被默认成内联函数。内联函数从源代码层看,有函数的结构,而在编译后,却不具备函数的性质。内联扩展是用来消除函数调用时的时间开销。它通常用于频繁执行的函数,对于小内存空间的函数非常受益。
使用内联函数的时候要注意:
递归函数不能定义为内联函数。
内联函数一般适合于不存在while和switch等复杂的结构且只有1~5条语句的小函数上,否则编译系统将该函数视为普通函数。
内联函数只能先定义后使用,否则编译系统也会把它认为是普通函数。
对内联函数不能进行异常的接口声明。
示例:一个简单的交换函数

inline void swap(int *a, int *b)
{
    int t = *a;
    *a = *b;
    *b = t;
}
预处理命令定义简单函数

可以用预处理命令 define 来定义简单函数:

#define  MAX_3(a, b, c) ( ((a > b ? a : b) > c) ? (a > b ? a : b) : c )
#define  MIN_3(a, b, c) ( ((a < b ? a : b) < c) ? (a < b ? a : b) : c )
#define  MAX_2(x, y)  ( x> y ? x : y )
#define  MIN_2(x, y)  ( x< y ? x : y )
#define  ARR_SIZE(a)  ( sizeof( (a) ) / sizeof( (a[0]) ) )
#define  MULTIPLE(m, n) ( (m%n == 0)?0:1 )
#define  AVE_3(a, b, c) (a+b+c)/3
#define  SUM_3(a, b, c) a+b+c
#define  SWAP(a, b){int t= a;a=b;b=t;}

5.19

c作用域规则

任何一种编程中,作用域是程序中定义的变量所存在的区域,超过该区域变量就不能被访问。C 语言中有三个地方可以声明变量:在函数或块内部的局部变量;在所有函数外部的全局变量‘在形式参数的函数参数定义中。

局部变量

在某个函数或块的内部声明的变量称为局部变量。它们只能被该函数或该代码块内部的语句使用。局部变量在函数外部是不可知的。

全局变量

全局变量是定义在函数外部,通常是在程序的顶部。全局变量在整个程序生命周期内都是有效的,在任意的函数内部能访问全局变量。全局变量可以被任何函数访问。也就是说,全局变量在声明后整个程序中都是可用的。

在程序中,局部变量和全局变量的名称可以相同,但是在函数内,如果两个名字相同,会使用局部变量值,全局变量不会被使用。

形式参数

函数的参数,形式参数,被当作该函数内的局部变量,如果与全局变量同名它们会优先使用。

除了函数是有作用域外,其实在 if、for、do-while 中也是有作用域的,若在这些语句块中初始化的话,到了其外部就无法访问。

初始化局部变量和全局变量

当局部变量被定义时,系统不会对其初始化,您必须自行对其初始化。定义全局变量时,系统会自动对其初始化(int:0。char:’\0‘。float:0。double:0。pointer:NULL)。
正确地初始化变量是一个良好的编程习惯,否则有时候程序可能会产生意想不到的结果,因为未初始化的变量会导致一些在内存位置中已经可用的垃圾值。

c数组

C 语言支持数组数据结构,它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。数组的声明并不是声明一个个单独的变量,比如 runoob0、runoob1、…、runoob99,而是声明一个数组变量,比如 runoob,然后使用 runoob[0]、runoob[1]、…、runoob[99] 来代表一个个单独的变量。所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素,最高的地址对应最后一个元素。数组中的特定元素可以通过索引访问,第一个索引值为 0。

声明数组

在 C 中要声明一个数组,需要指定元素的类型和元素的数量,如下所示:

type arrayName [ arraySize ];

这叫做一维数组。arraySize 必须是一个大于零的整数常量,type 可以是任意有效的 C 数据类型。例如,要声明一个类型为 double 的包含 10 个元素的数组 balance,声明语句如下:

double balance[10];

现在 balance 是一个可用的数组,可以容纳 10 个类型为 double 的数字。

初始化数组

在 C 中,您可以逐个初始化数组,也可以使用一个初始化语句,如下所示:

double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};

大括号 { } 之间的值的数目不能大于我们在数组声明时在方括号 [ ] 中指定的元素数目。如果您省略掉了数组的大小,数组的大小则为初始化时元素的个数。因此,如果:

double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};//您将创建一个数组,它与前一个实例中所创建的数组是完全相同的。

对于数组的初始化需要注意以下几点:1) 可以只给部分元素赋值,当 { } 中值的个数少于元素个数时,只给前面部分元素赋值。下面是一个为数组中某个元素赋值的实例:

balance[4] = 50.0;//把数组中第五个元素的值赋为 50.0。

所有的数组都是以 0 作为它们第一个元素的索引,也被称为基索引,数组的最后一个索引是数组的总大小减去 1。

访问数组元素

数组元素可以通过数组名称加索引进行访问。元素的索引是放在方括号内,跟在数组名称的后边。例如:

double salary = balance[9];//将把数组中第 10 个元素的值赋给 salary 变量。

(a+1)表示a数组中下标为1的元素,即a[2]。(a+1)表示a数组中下标为1的元素的地址,即&a[1]。
指针与数组名的区别。指针:也是一个变量,存储的数据是地址。数组名:代表的是该数组最开始的一个元素的地址。p 是个指针,p[i]与
(p+i)是等价的。区别:指针是一个变量,可以进行数值运算。数组名不是变量,不可以进行数值运算。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值