欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C与指针学习笔记

程序员文章站 2024-02-17 15:26:04
...

第一章 快速上手

1.1 简介

  1. c语言中所有的函数参数都是按值传递
  2. 应该使用typedef而不是#define来创建新的类型名,因为#define不能正确的处理指针。
int const *pci;//pci是一个指向常量的指针,pci的值可以修改
int *const pci;//pci是一个常量指针,pci的值不能修改
int const * const cpci;//都不允许修改

第三章 数据

基本数据类型

C语言只有整型 浮点型 指针 和聚合类型(数组 结构体)这4种基本数据类型。

整型

整型包括字符 短整型 整型 和长整型,分为unsigned和signed 。长整型至少应该与整型一样长,整型至少应该和短整型一样长。short int 至少16位,long int 至少32位,int究竟是16位还是32位由编译器决定。

枚举类型enum以整型的方式存储,如果某个符号名未赋值,那么它的值比前一个符号名值+1;。

浮点类型

浮点数包括float double和long double,所有浮点类型至少要能够容纳10-37~1037之间的任何值,浮点数字面值缺省情况下是double类型的。

指针

可以把内存想象成一间间房子,指针就是门牌号,房子里的物品就是内存的值。
指针常量:c语言中没有定义指针常量。

字符串常量:字符串通常存储于字符数组中,以NUL字节结尾。在程序中使用字符串常量会生成一个”指向字符的指针“,因此可以将一个字符串常量赋值给一个”指向字符的指针“,但是不能将一个字符串常量赋值给一个字符数组。

基本申明

说明符(一个或者多个)+声明表达式列表

声明数组

C语言编译器并不检查程序对数组下标的引用是否越界。

声明指针

int *message = "hello world" 

这条语句把message声明为一个指向字符的指针,并且把字符串常量中第一个字符的地址赋值给message。

typedef

typedef原则允许为各种数据类型定义新名字。

  typedef char *ptr_to_char
  ptr_to_char a;

这个声明把标识符ptr_to_char作为指向指针类型的新名字。a是一个指向字符的指针。应该使用typedef而不是#define 来创建新的类型名,因为#define无法处理指针类型。

#define d_ptr_to_char char *
d_ptr_to_char a, b;

上面代码正确的声明了a,但是b却被声明为一个字符。

常量const

int const a
const int a
a声明为一个整数,它的值不能被修改。有两种给常量赋值的方式:

  • 在声明时对它进行初始化

  • 在函数中声明const形参在函数调用时会得到实参的值。

    int const *pci;//pci指向整型常量的指针,可以修改指针的值,但你不能修改它所指向的值。
    int * const pci;//pci指向整型的常量指针,可以修改指向的值,但你不可以指针的值。
    int const * const pci;//无论是指针本身还是它指向的值都是常量,不允许修改。

作用域

编译器可以确定4种不同类型的作用域-文件作用域 函数作用域 代码块作用 和原型作用域

链接属性-external internal none

  • external 链接属性的标识符无论声明多少次,位于几个源文件都表示同一个实体。
  • internal 在同一个源文件内的所有声明都指向同一个实体。
  • none 该标识符的所有声明都指向不同的实体。
    注意:static 会把默认的external链接属性变成internal。

存储类型

有三个地方可以存储变量:普通内存 运行时堆栈 硬件寄存器

static关键字

  • static关键字放在代码块之外是修改变量的链接属性,从external变成internal,不修改存储属性。
  • static关键字放在代码块之内是修改变量的存储属性,从自动变量变为静态变量,链接属性和作用域不受影响。

第四章 语句

4.1 空语句

4.2 表达式语句

c语言不存在赋值语句,赋值是一种操作。意味着像以下这样的语句是完全合法的。

y+3;
getchar();
```

## 4.3 代码块

## 4.4 if语句
c语言不具备布尔类型,而是用整形来代替。

## 4.5 while语句
```
while( (ch = getchar()) != EOF && ch != '\n' )
```
## 4.6 for语句
。。。。。

#第五章 操作符和表达式
## 5.1 操作符
```
int x, xx[5];
sizeof(int);//返回整形变量的字节数
sizeof(x);//返回变量x所占据的字节数
sizeof(xx);//返回xx数组的长度,以字节为单位,此处为20
```

#第六章 指针
## 6.1 内存和地址
1. 内存中的每一个字对应一个地址,一个字可以是一个或者多个字节。


## 6.3 指针变量的内容
1. 变量的值就是分配给该变量的内存位置所存储的数值,指针变量也不列外。

## 6.4 间接访问操作符
1. 指针并不存在内建的间接访问属性,所以通过间接访问操作符访问指针所指向的位置。



#第七章 函数
##7.7总结
1. 函数形参都是通过传值方式调用的,实际传送的是实参的拷贝。
2. 数组名传递也是通过传值的方式传递的,它传给函数的是一个指向该数组的指针的拷贝。
3. 函数中的形参数组使用了下标引用操作,就会引发**间接访问** 操作,它实际访问的是实参数组的元素。这个行为被称为**传址调用**。

#第八章 数组
##8.1一维数组
1. 数组具有和指针完全不同的特征,只有当数组名在表达式中使用时,编译器才会为数组名产生一个**指针常量**。注意是指针常量而不是指针变量。
2. 数组名作为sizeof操作符时,sizeof返回整个数组的长度。
3. 下标绝不会比指针更有效率,但指针有时会比下标更有效率。

##8.2多维数组
```
int matrix[3][10];
```
matrix这个名字的值表示指向第一个元素的指针,所以matrix是一个指向一个包含10个元素数组的**指针**。
```
func(matrix);
```
func函数的原型应该是下面两种形式中的任何一种:
```
void func(int  (*mat)[10]);
void func(int mat[][10]);
```
把func写成下面的原型是**不正确的**:
```
void func(int **mat);
```
因为mat是一个指向整形指针的指针,它与指向整型数组的指针并不是一回事。

##8.3 指针数组
```
int *api[10];
```
下标引用的优先级高于间接访问的优先级,首先执行下标引用,所以api是一个数组;在获取到一个数组元素后,执行间接访问,间接访问的结果是一个整型,所以数组元素是一个整型指针。

#第九章 字符串
##9.1 字符串基础
1. NUL字节是字符串的终止符,但它本身并不是字符串的一部分,所以字符串的长度并不包括NUL字节。

#第十章 结构和联合
##10.1 结构成员
1. 结构成员使用(.)操作符访问
2. (.)操作符的优先级高于间接访问操作符,所以结构成员的间接访问需要添加括号,如下
```
void func(struct COMPLEX *cp);
(*cp).f;
```
这样不太方便,所以提供了->箭头操作符,箭头操作符左操作数必须是一个指向结构的指针。
```
cp->f
```
3. 结构的自引用
```
struct  SELF_REF1 {
           int a;
           struct SELF_REF1 b;
           int c;
};
非法
```
```
struct  SELF_REF1 {
           int a;
           struct SELF_REF1 *b;
           int c;
};
合法
```
##10.3 结构的存储分配

#第11章 动态内存分配
## 11.2 malloc和free
1. malloc从内存池提取一块内存,并向该程序返回一个指向这块内存的指针,但是这块内存并没有初始化
2. 对每个malloc返回的指针都要进行检查,确保非NULL
3. 向free传递一个NULL参数不会产生任何效果
4. void *类型的指针可以转换为其他任何类型的指针

#第十三章 高级指针话题
##13.3 函数指针
```
int  f(int);
int  (*pf)( int ) = &f;
```
初始化表达式中的&操作符是可选的,因为**函数名**在使用时总是由编译器把它转换为**函数指针**。