C语言学习笔记(持续更新)

1.定义与声明的区别

(1)是否需要分配存储空间。

(2)在一个作用域中可以重复声明,但不能重复定义。这是由(1)决定的,可以重复几次告诉编译器某个变量、函数已经在别处定义了,但不能重复多次地让编译器为同一个变量、函数分配不同的存储空间。

extern inta;              //声明一个全局变量a

inta;                          //定义一个全局变量a

extern int a=0;        //定义一个全局变量a 并给初值。一旦给予赋值,一定是定义,定义才会分配存储空间。

int a=0;                    //定义一个全局变量a,并给初值,声明之后你不能直接使用这个变量,需要定义之后才能使用。

第四个等于第三个,都是定义一个可以被外部使用的全局变量,并给初值。

糊涂了吧,他们看上去可真像。但是定义只能出现在一处。也就是说,不管是int a;还是inta=0;都只能出现一次,而那个extern int a可以出现很多次。

当你要引用一个全局变量的时候,你就要声明extern int a;这时候extern不能省略,因为省略了,就变成inta;这是一个定义,不是声明。

函数的定义、声明

函数的定义和声明也是一样,定义需要分配存储空间;声明只是告诉编译器这个函数已经在别处定义过了。

函数的定义和声明比较好区分。有函数体的即为定义,不带函数体即为声明。

 

2.指针数组

char *p[4]:定义了一个有4个元素的数组,这个数组是由指针构成,且全部指向char型变量。

例子:

char *p="abc123ABC",char* p是一个指针,根本没分配内存,他指向的"abc123ABC"是只读的,不能改变,若给他赋值会出错。

注意:指针是不分配内存的,它指向的是系统的只读的内存,而数组是分配内存的,就是将系统的只读的内存里面的值复制到它的内存里面,因此可读写。

 

3.二维数组的指针

int a[2][3]————int (*p) [3]————p指向a[0][0]的地址

p+1指向a[1][0]的地址(地址的地址),与a+1的作用是一样的。

 如何表示a[1][1]的地址呢?要记住,二维数组的指针可以认为是两层指针(地址的地址),要想表示一个二维数组具体元素的地址,剥掉一层指针(加*即可)再平移即可,即*(p+1)+1.*(p+1)表示a[1][0]的地址,再平移1位即可。

 如何表示a[1][1]的值呢? 在剥掉一层指针即 *(*(p+1)+1)

 

4.

const char a[] = "abcd";        //abc存储在堆栈中  
const char *b= "abcd";         //abc存储在静态存储区  
准确的说,上面两个“abc"都是存储在静态存储区,即常量区。常量区是可读不可写的。所以任何试图对常量区进行写的操作都是非法的。那么为什么a[]="abc"; 可以写呢?  

答案就在a[] = "abc";会有一个额外的拷贝过程,即把常量区的 "abc"拷贝到栈内存去,所以就可以写了。

如a[2]=’r’,是合法的,而b[2]=’r’就是非法的,因为字符串常量无法改变。但是,指针的指向却是可以更改的,如

char *a;

a= "abcd";

a= "efgh"; 

char * str是存储在全局静态存储区,所以,虽然是局部变量但函数返回后依然可以拿到正确的值!
char str[] 是存储在栈上的,local variable,函数返回后,OS就收回空间了,就不复存在了,所以,拿不到正确的结果!

 char str[]="name";与char str[5];str="name"的不同之处在哪,能不能从内存分配的角度讲一讲,我知道数组名字是一个常量地址(指针),第一个为什么对,第二个为什么错?

第二个先定义了一个数组,要知道数组名str是数组分配到的空间的首地址,str="name"应该是等号两边类型不匹配的错误。一般的常量应该没有内存地址的,除非有某个变量指向了该常量。

数组名是地址常量,那么常量当然不允许被重新赋值。

"name"是一个字符串常量他存储在常量存储区,只能用一个指针指向它却不允许改变:char*p;p="name";一般情况下char str[]="name";数组是在栈上的空间由编译器分配,内容可以由用户改变。

 

5.                           二维数组a的有关指针

表示形式

含义

a

二维数组名,指向一维数组a[0],即0行首地址

a[0],*(a+0),*a

0行0列元素地址

a+1,&a[1]

1行首地址

a[1],*(a+1)

1行0列元素a[1][0]

a[1]+2,*(a+1)+2,&a[1][2]

1行2列元素a[1][2]

*(a[1]+2),*(*(a+1)+2),a[1][2]

1行2列元素a[1][2]的值

 

谨记实参和形参的数据类型必须一致,不能用表示行地址的量去对应元素地址的量,亦不能用元素地址的量去对应行地址的量。

如:

void average(float*p, int n);

void search (float(*p)[4], int n);

floatscore[3][4]={{65,67,70,60},{80,87,90,81},{90,99,100,98}};

average(*score,12);

search(score,2);

float(*p)[4]为指向(由4个元素组成的)一维数组的指针变量,实际上其值对应的是行地址,所以float(*p)[4]对应score,而不是*score(元素地址,元素值应该就是*(*score)—score[0][0]),

而float*是元素的地址,对应的自然就是*score。

 

6.左值(有名字的变量)和右值(没有名字的临时变量):C/C++语言中可以放在赋值符号左边的变量,左值表示存储在计算机内存的对象,左值相当于地址值。右值:当一个符号或者常量放在操作符右边的时候,计算机就读取他们的“右值”,也就是其代表的真实值,右值相当于数据值.

 

7.静态本地变量:实际上是特殊的全局变量,因为静态本地变量和全局变量位于同一内存区域(局部变量不在同一区域的,内存地址相差很大,见翁恺12.1课时),故静态本地变量具有全局的生存期,函数内的局部作用域。

 

8.实际上结构数组相当于一个二维构造, 第一维是结构数组元素,  每个元素是一个结构变量, 第二维才是结构成员。

struct
{
    charname[8];
    charsex[4];
    intage;  
    charaddr[40];
}student[40];
则此结构数组成员的访问是以数组元素为结构变量的,  其形式为: 结构数组元素.成员名
例如:
student[0].name
student[30].age

 

9.函数的调用能且只能得到一个返回值(即函数值),而使用指针变量作参数,可以得到多个变量的返回值。

 

10.return;的意思:return直接用的意思是当满足某个条件时,自动跳出整个函数体,不让函数作任何事情,提高代码的运行效率。带表达式的return如returna的意思是返回一个值给参数。

 

11.指针作为返回值(百度文库):GetMax函数中,我们用临时变量temp比较记录全局数组score里最大的元素,同时用pos记录最大的元素的数组下标号。循环结束后,返回的是数组中值最大的元素的地址值,即该元素的指针值。注意因为数组是全局变量,GetMax函数调用结束后,数组元素在内存中仍然存在,因此GetMax函数返回的指针值是有效的。

12.函数中遇到return语句就不再执行函数剩下的内容,直接返回。有返回值的函数return后面需要加个类型匹配的量,无返回值的话return后面留空即可。

例如:

fun1()
{
  return;
  printf("fun1") ;
}
fun2()
{
  fun1();
  printf("fun2") ;
}
main()
{
  fun2();
}
此时main函数调用fun2,然后fun2调用fun1,fun1直接return了,fun1没有打印,但是fun2打印了,如果想不打印fun2,把fun1里面的return改为exit就好了。


13.动态语言,是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化。比如众所周知的ECMAScript(JavaScript)便是一个动态语言。除此之外如Ruby、Python等也都属于动态语言,而C、C++等语言则不属于动态语言。

14.图灵完备:在可计算理论中,当一组数据操作的规则(一组指令集,编程语言,或者元胞自动机)满足任意数据按照一定的顺序可以计算出结果,被称为图灵完备(turing complete)。一个有图灵完备指令集的设备被定义为通用计算机。如果是图灵完备的,它(计算机设备)有能力执行条件跳转(“if” 和 “goto”语句)以及改变内存数据。 如果某个东西展现出了图灵完备,它就有能力表现出可以模拟原始计算机,而即使最简单的计算机也能模拟出最复杂的计算机。所有的通用编程语言和现代计算机的指令集都是图灵完备的(C++ template就是图灵完备的),都能解决内存有限的问题。图灵完备的机器都被定义有无限内存,但是机器指令集却通常定义为只工作在特定的,有限数量的RAM上。

一门语言为什么要图灵完备呢?可以这么理解:
一台计算机也是一个图灵机,一个图灵完备的语言意味着这个语言可以使用计算机完成任何计算机可以完成的任务,也就能够发挥计算机的所有能力。(这句话有点绕口)
反之,一个图灵不完备的语言,就意味着不能发挥计算机的所有能力。


15.墨菲定律:事情如果有变坏的可能,不管这种可能性有多小,它总会发生。


16." "还是<>:    前者要求编译器先在当前这个 .c 文件所在的目录(暗示当前编写的.c文件和需要引用的函数在同一目录)去找,如果没有,再到系统指定的位置去找(IDE安装时就确定了的,即下文所述的工程目录);而后者不找当前目录,只在系统标准库的目录里面找。一般情况下,如果是自己编写的头文件就用前者。(P.S.编译器知道自己的标准库的头文件在哪儿。当然,也可以用命令行cmd来找)

  把自己所写的函数(.h文件)放在安装程序时的工程目录下(C:\Program Files\Microsoft Visual Studio\VC98\Include),再调用即可(头文件#include“max.h”)




用双引号意味着max.h和我引用它的.c文件在一个目录下或者在标准库目录里,都可以。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值