C语言笔记6--指针与数组
2016-11-17 14:49
309 查看
C语言笔记6--指针与数组
总论:
指针是一种保存变量地址的变量。在C语言中,指针的使用非常广泛,原因之一是,指针常常是表达式某个计算的唯一途径,另一个原因是,同其他方法比较起来,使用指针通常可以生产更高效,更紧凑的代码。
指针与地址
指针是一种保存变量地址的变量,它里面存储的数值被解释成为内存里的一个地址。
如:c 的类型char ,并且p是指向c的指针。
一元运算符* 是间接寻址或间接引用运算符。当它作用于指针时,将访问指针所指向的对象。
注:指针的声明使用“*”为了便于记忆。指针必须指向某种特定的数据类型。由于指针也是变量,所以在程序中可以直接使用。
指针与函数参数
由于C语言是以传值的方式将参数值传递给被调用函数,因此,被调用函数不能直接修改主调函数中变量的值。
指针可以实现这一目标:主调程序将指向所要交换的变量的指针传递给被调用函数,即:
swap 函数的所有参数都声明为指针,并且通过这些指针来间接访问它们指向的操作数。
注:指针参数使得被调用函数能够访问和修改主调函数中对象的值。
数组
1、声明数组的通用格式:
3、sizeof 作用于数组名时,得到的是整个数组中的字节数。作用于元素时,得到的是该元素的字节数。
4、只有定义数组时才能初始化,之后就不行了。可以部分初始化,如:
指针与数组
在C语言中,通过数组下标所能完成的任何操作都可可通过指针来实现,一般来说,用指针编写的程序比用数组下表编写的程序执行速度快,但另一方面,用指针实现的程序理解起来稍微困难一些。
声明:
声明:
赋值语句:
赋值语句:
说明:
如果pa指向数组中的某个特定元素,那么,根据指针运算符的定义,pa + 1 将指向下一个元素,pa + i 将指向pa所指向数组元素之后的第i 个元素。
因此,如果指针pa 指向a[0],那么*(pa + 1)引用的是数组元素a[1]的内容,pa + i 是数组元素a[i]的地址,*(pa + i) 引用的是数组元素a[i]的内容。
无论数组a中的元素的类型或数组长度时什么,上面的结论都成立。
赋值语句:
结论:
对数组元素a[i]的引用也可以写成*(a + i)这种形式。&a[i]和a + i的含义也是相同的。相应地,如果pa 是一个地址,那么,在表达式中也可以在它的后面加下标,pa[i] 与 *(pa + i)是等价的。
注:
1、数组名和指针之间有个不同之处,指针是一个变量,因此,在C语言中,语句pa = a 和pa++都是合法的。
2、 但是数组名不是变量,因此,类似于a = pa 和 a ++ 形式的语发是非法的。
3、注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。
4、当把数组名传递给一个函数时,实际上传递的是该数组第一个元素的地址,在被调用函数中,该参数是一个局部变量,因此,数组名参数必须是一个指针。如:
地址算术运算
指针的运算规则:
有效的指针运算包括相同类型指针之间的赋值运算;
指针同整数之间的加法或减法运算;
指向相同数组中元素的两个指针间的减法或比较运算;
将指针赋值为0(NULL)或指针与0(NULL)之间的比较运算;
字符串与函数
字符串常量是一个字符数组。
如:"hello, would"
在字符串的内部表示中,字符数组以空字符'\0'结尾,所以,程序可以通过检查空字符找到字符数组的结尾。
字符串常量占据的存存储单元数也因此比双引号奶的字符数大1。
字符串常量最常见的用法就是作为函数参数,如:printf("hello, would\n");
当类似于这样的一个字符串出现在程序中是,实际上是通过字符指针访问该字符串的。
在上述语句中,printf 接受的是一个指向字符数组第一个字符的指针。
注:字符串常量可以通过一个指向其第一个元素的指针访问。
array 是一个仅仅足以存放初始化字符串以及空字符'\0'的数组。数组中的单个字符可以进行修改,但array 始终指向同一个存储位置。
parray 是一个指针,其初值指向一个字符串常量,之后它可以被修改以指向其他地址,但试图修改字符串的内容,结果是没有意义的。
解读复杂指针声明
右左法则:
首先从标识符开始阅读,然后往右看,再往左看。每当遇到圆括号时,就应该调转阅读方向。一旦解析完括号里所有的东西,就跳出括号。
重复这个过程直到整个声明解析完毕。
指针数组 & 数组指针
指针数组:首先它是一个数组,数组的元素都是指针,也称为"储存指针的数组"。
数组指针:首先它是一个指针,它指向一个数组。也可以理解为"数组的指针。"
各代表什么?要弄清这个问题,首先要知道[ ]优先级比*要高。
p1先与[ ]结合,构成一个数组定义,数组名为p1,int*修饰的是数组的内容,即数组的每个元素。
p2中()的优先级比[ ]高,所以*号先与P2构成一个指针的定义,指针变量名为P2,int修饰的是数组的内容,即数组的每个元素。数组在这里没有名子。
函数指针 & 指针函数
函数指针:指向函数的指针变量。
指针函数:带指针的函数,也就是返回指针的函数。
指针常量 & 常量指针
a. 可以先把类型名去掉,然后看 const 离谁近,就修饰谁。
b. 也可以const 在 * 左边的为常量指针,const 在 * 右边的为指针常量。
野指针
野指针是怎么造成的?
1. 指针变量被创建而没有初始化。
2. 指针 p 被 free 或者 delete 之后, 没有置为 NULL。
总论:
指针是一种保存变量地址的变量。在C语言中,指针的使用非常广泛,原因之一是,指针常常是表达式某个计算的唯一途径,另一个原因是,同其他方法比较起来,使用指针通常可以生产更高效,更紧凑的代码。
指针与地址
指针是一种保存变量地址的变量,它里面存储的数值被解释成为内存里的一个地址。
如:c 的类型char ,并且p是指向c的指针。
char c; char *p; p = &c; /*将把c 的地址赋值给变量p ,我们称p 为“指向”c的指针。*/一元运算符& 可用于取一个对象的地址。地址运算符& 只能应用于内存中的对象,即变量与数组元素。不能作用于表达式,常量或寄存器retister 变量。
一元运算符* 是间接寻址或间接引用运算符。当它作用于指针时,将访问指针所指向的对象。
注:指针的声明使用“*”为了便于记忆。指针必须指向某种特定的数据类型。由于指针也是变量,所以在程序中可以直接使用。
指针与函数参数
由于C语言是以传值的方式将参数值传递给被调用函数,因此,被调用函数不能直接修改主调函数中变量的值。
指针可以实现这一目标:主调程序将指向所要交换的变量的指针传递给被调用函数,即:
swap(&a,&b);由于一元运算符&用来取变量的地址,这样&a 就是一个指向变量a的指针。
swap 函数的所有参数都声明为指针,并且通过这些指针来间接访问它们指向的操作数。
void swap(int *pi,int *pj) { int temp; temp = *pi; *pi = *pj; *pj = temp; }
注:指针参数使得被调用函数能够访问和修改主调函数中对象的值。
数组
1、声明数组的通用格式:
typeName arrayName[arraySize] int a[5]; //(编译器不会检查使用的下标是否有效。)2、如果没有初始化函数中定义的数组,其元素的值为以前驻留在该内存中的值。(与函数中的变量一样)
3、sizeof 作用于数组名时,得到的是整个数组中的字节数。作用于元素时,得到的是该元素的字节数。
4、只有定义数组时才能初始化,之后就不行了。可以部分初始化,如:
int a[5] = {1,2}; //部分初始化时,编译器把其他元素设置为0。 int b[] = {1,2,3,4,5}; //让编译器计算元素个数。5、使用列表初始化数组时,可以省略等号(=);大括号内不包含任何内容时,默认所有元素为0;列表初始化禁止缩窄转换。
指针与数组
在C语言中,通过数组下标所能完成的任何操作都可可通过指针来实现,一般来说,用指针编写的程序比用数组下表编写的程序执行速度快,但另一方面,用指针实现的程序理解起来稍微困难一些。
声明:
int a[10];定义了一个长度为10的数组a。换句话说,它定义了一个由10个对象组成的集合。
声明:
int *pa;则声明了一个指向整型对象的指针。
赋值语句:
pa = &a[0];则可以将指针pa指向数组a的第0个元素。也就是说,pa的值为数组元素a[0]的地址。
赋值语句:
int x = *pa;将把数组元素a[0]中的内容复制到变量x中。
说明:
如果pa指向数组中的某个特定元素,那么,根据指针运算符的定义,pa + 1 将指向下一个元素,pa + i 将指向pa所指向数组元素之后的第i 个元素。
因此,如果指针pa 指向a[0],那么*(pa + 1)引用的是数组元素a[1]的内容,pa + i 是数组元素a[i]的地址,*(pa + i) 引用的是数组元素a[i]的内容。
无论数组a中的元素的类型或数组长度时什么,上面的结论都成立。
赋值语句:
pa = &a[0];其中,pa与a具有相同的值,因为数组名所代表的就是该数组最开始的一个元素的地址,所以,赋值语句pa = &a[0]也可以写成:
pa = a;
结论:
对数组元素a[i]的引用也可以写成*(a + i)这种形式。&a[i]和a + i的含义也是相同的。相应地,如果pa 是一个地址,那么,在表达式中也可以在它的后面加下标,pa[i] 与 *(pa + i)是等价的。
注:
1、数组名和指针之间有个不同之处,指针是一个变量,因此,在C语言中,语句pa = a 和pa++都是合法的。
2、 但是数组名不是变量,因此,类似于a = pa 和 a ++ 形式的语发是非法的。
3、注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。
4、当把数组名传递给一个函数时,实际上传递的是该数组第一个元素的地址,在被调用函数中,该参数是一个局部变量,因此,数组名参数必须是一个指针。如:
int strlen(char *s) { int n; for(n = 0; *s != '\0'; s++) { n++; } return n; }因此,类似于下面这样的函数调用,都可以正确的执行。
void main(void) { char array[] = "hello, would"; char *ptr = "hello, would"; strlen("hello, would"); strlen(array); strlen(ptr); }
地址算术运算
指针的运算规则:
有效的指针运算包括相同类型指针之间的赋值运算;
指针同整数之间的加法或减法运算;
指向相同数组中元素的两个指针间的减法或比较运算;
将指针赋值为0(NULL)或指针与0(NULL)之间的比较运算;
字符串与函数
字符串常量是一个字符数组。
如:"hello, would"
在字符串的内部表示中,字符数组以空字符'\0'结尾,所以,程序可以通过检查空字符找到字符数组的结尾。
字符串常量占据的存存储单元数也因此比双引号奶的字符数大1。
字符串常量最常见的用法就是作为函数参数,如:printf("hello, would\n");
当类似于这样的一个字符串出现在程序中是,实际上是通过字符指针访问该字符串的。
在上述语句中,printf 接受的是一个指向字符数组第一个字符的指针。
注:字符串常量可以通过一个指向其第一个元素的指针访问。
char array[] = "hello, would"; /*定义一个数组*/ char *parray = "hello, would"; /*定义一个指针*/上述声明中:
array 是一个仅仅足以存放初始化字符串以及空字符'\0'的数组。数组中的单个字符可以进行修改,但array 始终指向同一个存储位置。
parray 是一个指针,其初值指向一个字符串常量,之后它可以被修改以指向其他地址,但试图修改字符串的内容,结果是没有意义的。
解读复杂指针声明
右左法则:
首先从标识符开始阅读,然后往右看,再往左看。每当遇到圆括号时,就应该调转阅读方向。一旦解析完括号里所有的东西,就跳出括号。
重复这个过程直到整个声明解析完毕。
int *a[10] // 首先 a 右边是[],说明 a 是一个具有10个元素的数组 // 其次 a 左边是 int*,说明 a 的元素是 int 类型的指针 int (*a)[10] // 首先 a 左边是一个 * 号,说明 a 是一个指针 // 跳出括号,右边是 [], 说明 a 是一个指向具有10个元素的数组的指针 // 左边是 int,说明元素的类型是 int int (*func)(int *p); // 首先找到 func,它左边是一个 * 号,这说明 func 是一个指针 // 然后跳出这个圆括号,先看右边,也是个圆括号,这说明 (*func) 是个函数,而 func 是指向这个函数的指针 // 这个函数具有 int* 类型的参数,返回值类型为 int int (*func[5])(int* p) // 首先找到 func, 右边是[],说明 func 是一个具有5个元素的数组 // 其次 func 左边有一个 *,说明 func 的元素是指针,要注意 * 不是修饰func的,而是修饰 func[5]的 // 跳出这个括号,右边也是一个括号,说明 func 数组的元素是函数类型的指针
指针数组 & 数组指针
指针数组:首先它是一个数组,数组的元素都是指针,也称为"储存指针的数组"。
数组指针:首先它是一个指针,它指向一个数组。也可以理解为"数组的指针。"
int *p1[10] int (*p2)[10]
各代表什么?要弄清这个问题,首先要知道[ ]优先级比*要高。
p1先与[ ]结合,构成一个数组定义,数组名为p1,int*修饰的是数组的内容,即数组的每个元素。
p2中()的优先级比[ ]高,所以*号先与P2构成一个指针的定义,指针变量名为P2,int修饰的是数组的内容,即数组的每个元素。数组在这里没有名子。
函数指针 & 指针函数
函数指针:指向函数的指针变量。
指针函数:带指针的函数,也就是返回指针的函数。
char * fun(char* a, char* b) //定义为 指针函数 {...... } int main() { char* (*p)(char* p1, char* p2); //定义为 函数指针 p = &fun; //把函数地址赋给他 //p = fun; //这样写也行 (*p)("aa", "bb"); //使用函数指针 return 0; }
指针常量 & 常量指针
const char* p1; //常量指针,指向常量的指针 char const* p2; char* const p3; //指针常量,指针是常量
a. 可以先把类型名去掉,然后看 const 离谁近,就修饰谁。
b. 也可以const 在 * 左边的为常量指针,const 在 * 右边的为指针常量。
野指针
野指针是怎么造成的?
1. 指针变量被创建而没有初始化。
2. 指针 p 被 free 或者 delete 之后, 没有置为 NULL。
相关文章推荐
- C语言学习笔记【指针04】指针数组与指向指针的指针 推荐
- iOS笔记之_C语言数组与指针
- c语言笔记——指针与数组
- C语言学习笔记22——数组参数和指针参数
- C语言学习笔记之成员数组和指针
- C语言深度剖析笔记(指针和数组)
- 【c语言学习笔记】指针数组和数组指针以及在做题的时候遇到的问题
- C语言基本概念笔记《三》之指针,数组,动态数组的创建
- C语言学习笔记17——数组与指针
- C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com
- C语言学习笔记(20) 数组参数和指针参数分析
- 黑马程序员-IOS笔记-C语言中的字符串数组 指针
- C语言学习笔记19——数组指针和指针数组分析
- 数组和指针————C语言学习笔记1
- C语言学习笔记之指向数组元素的指针和指向数组的指针
- 黑马程序员-IOS笔记-C语言中的指针与数组
- C语言学习笔记(19) 多维数组和多维指针分析
- C语言学习笔记21——多维数组和多维指针
- C语言深度剖析学习笔记-指针、数组、内存、函数
- C语言学习笔记(18) 指针数组和数组指针分析