指针是c语言的灵魂

-----------------------------------------------------------------------------

# include <stdio.h>





int main(){

int *p;  //p是变量名,int *表示p变量存放的是int类型变量的地址,p是一个指针变量

int i = 3;



//p = i; 这样写是错误的

//p = 4; 这样写是错误的

p = &i;  //将i变量的地址给p变量

//p保存了i的地址,因此p指向i,修改p的值不影响i的值,修改i的值也不影响p的值



return 0;

}

-----------------------------------------------------------------------------

# include <stdio.h>





int main(){

int *p; //不表示定义了一个名字叫做 *p的变量

//应该这样理解:p是变量名,p变量的数据类型是 int *类型

//int *类型实际就是存放int变量地址的类型





int i = 3;



p = &i;



printf("*P = %d\n", *p);

printf("i = %d\n", i);

return 0;

}

1.如果p是个指针变量,并且p存放了普通变量i的地址,则p指向了普通变量

2.*P 完全等同于 普通变量i  (有i出现的地方都可以替换成*p)

------------------------------------------------------------------------------

指针和指针变量的区别:

1.指针就是地址,地址就是指针

地址就是内存单元的编号,所以指针就是内存单元的编号

2.指针变量存放地址的变量

指针变量是存放指针的变量,也就是说指针变量是存放内存单元编号的变量

3.指针和指针变量是两个不同的概念

但是要注意通常我们叙述时会把指针变量简称为指针,实际它们的含义不一样

一、指针的重要性

1.表示一些复杂的数据结构

2.快速的传递数据

3.使函数返回一个以上的值(函数只能返回一个值)

---------------------------------------------------------

# include <stdio.h>





int f(int a, int b);

void g(int * p ,int * q);





int main(void){



int a = 100;

int b = 200;



// a = f(a, b);

g(&a, &b);

printf("a = %d, b = %d\n", a, b);



return 0;

}

//只能修改一个值

int f(int a, int b){



return 1;

}

//这样被调函数可以修改主调函数一个以上的值

void g(int * p ,int * q){

*p = 1;

*q = 2;

}

---------------------------------------------------------

4.能直接访问硬件

5.能够方便的处理字符串

6.是理解面向对象语言中引用的基础

总结:指针是c语言的灵魂,是和其他语言的区别

二、指针的定义

地址

内存单元的编号,地址是从零开始的非负整数。

范围:

     控制总线

CPU <---->    数据总线  <----->  内存条

     地址总线

控制线控制数据传输的方向 

数据线是传输数据

地址线是确定是控制哪个内存单元



cup<----->  数据总线 <-----> 内存条

一根线控制两个 0和1

两根线控制四个

n根线控制2的n次方个单元(字节)(每个单元是8位)



32位机 2x10^32

1G=2X10^30B(字节)

2x10^32 ~= 2X10^30*4  所以内存最大4G

4G  [0——4G-1]


指针

指针就是地址,地址就是指针,指针变量就是存放内存单元编号的变量。

指针和指针变量是两个不同的概念

指针本质就是一个操作受限(不能运算,只是编号)的非负整数(地址)

三、指针的分类

1.基本类型指针

 //就是上面的代码

--------------------------------------------------------------------------

指针常见错误1

# include <stdio.h>





int main(void){

int *p;  //p指向一个垃圾值的地址,也就是一个垃圾地址

int i = 5;



*p = i;  // 就是将i的值给了一个不知道的地址,这样写不对

printf("%d\n", *p);



return 0;

}

常见错误2

# include <stdio.h>





int main(void){

int i = 5;

int *p;

int *q;



p = &i

//*q = p;  语法编译出错

//*q = *p;  error  q指向一个垃圾地址

q = p;  // error 可以读 q里面的垃圾地址,但是不能读*q的值,没有控制权限。

printf("%d\n", *q);



return 0;

}

--------------------------------------------------------------------------

/*

一个经典指针程序

*/

# include <stdio.h>





void huhuan(int i, int j);

void zhizhenhuhuan(int * a, int * b);

void huhuan3(int * a, int * b);





int main(void){

int a = 3;

int b = 5;



// huhuan(a, b);

// zhizhenhuhuan(&a, &b);

huhuan3(&a, &b);





printf("a = %d,b = %d\n", a, b);





return 0;

}





void huhuan(int a, int b){  //不能完成互换,a,b是形参,单独分配内存

int t;



t = a;

a = b;

b = t;

}





void zhizhenhuhuan(int * a, int * b){ //不能完成互换,互换了指针的指向

int * t;





t = a;

a = b;

b = t;

}





void huhuan3(int * a, int * b){  //可以完成互换,传递的是地址,交换的是地址指向的值

int t;





t = *a;

*a = *b;

*b = t;

}

---------------------------------------------------------------------------

*的含义

1.乘法   c = a*b;

2.定义指针变量 int * p;

3.取值运算符 *p

---------------------------------------------------------------------------

2.指针和数组的关系

 指针和一维数组

数组名

一维数组名是个指针常量

它存放的是数组第一个元素地址

----------------------------------------------------------------

int a[5];

int b[5];

a = b 是错误的  a,b都是常量

-----------------------------------------------------------------

# include <stdio.h>





int main(void){

int a[5];



printf("%#x\n", &a[0]);

printf("%#x\n", a);





return 0;

}

输出结果:0x12ff6c

 0x12ff6c

----------------------------------------------------------------

下标和指针的关系

如果p是个指针变量,则

p[i]永远等价于 *(p+i)

确定一个一维数组需要两个参数

数组第一个元素的地址

数组的长度

-------------------------------------------------------------------------

//f函数可以输出任何一个一维数组的内容

# include <stdio.h>





void f(int * pArr, int len){

int i;

for (i=0; i<len; i++)

printf("%d  ", *(pArr+i));

printf("\n");

}

int main(void){

int a[5] = {1, 2, 3, 4, 5};

int b[6] = {-1, -2, -3, 4, 5, -6};

int c[100] = {1, 99, 22, 33};



f(a, 5); //确定一个数组:数组首地址和长度

f(b, 6);

f(c, 100);



return 0;

}

-------------------------------------------------------------------------

# include <stdio.h>





void f(int * pArr, int len){

pArr[3] = 88;  //pArr[3]等价于a[3]也等价于*(a+3)和*(pArr+3) 

  // *a==a[0]

}





int main(void){

int a[6] = {1, 2, 3, 4, 5, 6};



printf("%d\n", a[3]);

f(a, 6);  // a和pArr都指向数组的第一个元素

printf("%d\n", *(a+3));



return 0;

}

-------------------------------------------------------------------------

指针变量的运算

指针变量不能相加,不能相乘,也不能相除(这些运算没有意义)

如果两个指针变量指向的是同一块连续空间中得不同的存储单元

则这两个指针才可以相减(这样减才有意义)

------------------------------------------------------------------------------

# include <stdio.h>





int main(void){

int i = 5;

int j = 10;

int * p = &i;

int * q = &j;

//此时p和q不能相减

int a[5];

p = &a[2];

q = &a[4];





printf("相减的结果为:%d\n", p-q);

//此时p和q可以相减,相减的值指p和q单元相隔的个数





return 0;

}

结果为:相减的结果为:-2

---------------------------------------------------------------------------------

一个指针变量到底占几个字节

预备知识:

sizeof(数据类型);或者 sizeof(变量名);

返回该数据类型所占的字节数

例如: sizeof(int) = 4 sizeof(char) = 1

假设p指向的char类型变量(1个字节)

假设p指向的int类型变量(4个字节)

假设p指向的double类型变量(8个字节)

p q r 本身所占的字节数是否一样

---------------------------------------------------------------------------

# include <stdio.h>





int main(void){

char ch = 'A';

int i = 90;

double x = 66.6;

char * p = &ch;

int *q = &i;

double *r = &x;



printf("%d  %d  %d\n", sizeof(p), sizeof(q), sizeof(r));

}

输出的结果:4  4  4

内存中一个字节为一个单元,所以double中有8个编号,

只用首字节的编号代表该变量的内存编号,用该变量类型

指明下面连续单元的个数

如: int * p;  int i = 5; p = &i;

p------>地址1101011(i的首地址)

int-------表示有四个字节

----------------------------------------------------------------------------

 指针和二维数组

3.指针和函数的关系



4.指针和结构体的关系



5.多级指针

----------------------------------------------------------------------------------

# include <stdio.h>





int main(void){

int i = 10;

int * p = &i;

int ** q = &p;

int *** r = &q;



printf("i = %d\n", ***r);





return 0;

}

结果: i = 10

-----------------------------------------------------------------------------------

专题:

动态内存分配

传统数组的缺点

1.数组的长度必须事先制定,且只能是常整数,不能是变量

 例如: int len = 5; int a[len];  //error

2.传统形式定义的数组,该数组的内存程序员无法手动释放

------------------------------------------------------------------------------

# include <stdio.h>





void f(void){

int a[5] = {1, 2, 3, 4, 5};

//这二十个字节的存储空间程序员无法手动编程释放它

//只能在本函数运行完毕时由系统自动释放

}





int main(void){

return 0;

}

------------------------------------------------------------------------------

3.数组的长度不能再函数运行的过程中动态的扩充或缩小

4.A函数定义的数组,在A函数运行期间可以被其它函数使用,

 但A函数运行完毕之后,A函数中的数组将无法在被其它函数使用

 静态数组不能跨函数使用

-------------------------------------------------------------------------

# include <stdio.h>

void g(int *pArr, int len){

pArr[2] = 88;

}

void f(void){

int a[5] = {1, 2, 3, 4, 5};  //f运行期间g();函数可以使用

g(a, 5);
//当f运行完毕数组a空间被释放

printf("%d\n", a[2]);

}





int main(void){

return 0;

}

--------------------------------------------------------------------------

为什么需要动态分配

动态数组很好的解决了传统数组的上面四个缺陷

动态内存分配的举例——动态数组的构造

----------------------------------------------------------------------------

/*

2012年2月5日15:00:25

malloc 是 memory(内存) allocate(分配)的缩写

*/

# include <stdio.h.

# include <malloc.h>  //头文件





int main(void){

int i = 5; //静态分配了四个字节

int * p = (int *)malloc(4);  //把返回的地址强制转换为整形变量的地址

/*

1.要使用malloc函数,必须添加malloc.h这个头文件

2.malloc函数只有一个形参,并且是整型

3.4表示请求系统为本程序分配4个字节

4.malloc函数只能返回第一个字节的地址

5.上面一行代码分配了8个字节,p变量占4个字节,p所指向的内存也占4个字节

6.p本身所占的内存是静态分配的,p所指向的内存是动态分配的

*/

*p = 5; //*p代表整形变量,只不过*p这个整形变量的内存分配方式和i分配不同

free(p);  //表示把p所指向的内存给释放掉

printf("同志们好!\n");



return 0;

}

----------------------------------------------------------------------------

# include <stdio.h>

# include <malloc.h>





void f(int * q){

*q = 200;

free(q);  //把q指向的内存释放掉 和 free(p)等价

}

int main(void){

int * p = (int *)malloc(sizeof(int));

*p = 10;



printf("%d\n", *p);   //10

f(p);  //通过f()修改p指向内存的值

printf("%d\n", *p); //p指向的内存已经释放,所以会出错



return 0;

}

----------------------------------------------------------------------------

/*

2012年2月5日15:37:36

动态一维数组示例

*/

# include <stdio.h>

# include <malloc.h>





int main(void){

int a[5]; //包含20字节

int i;

int len;

int *pArr;



printf("请输入你要存放的元素个数:");

scanf("%d", &len);

pArr = (int *)malloc(4*len);  //pArr指向前4个字节  类似于 int pArr[len];

// pArr+1 就指向第5到第8个字节


//动态的构造了一个int类型的一维数组,数组名 pArr

for (i=0; i<len; i++)  //对一维数组进行赋值

scanf("%d", &pArr[i]);



printf("一维数组的内容是:\n");

for(i=0; i<len; i++)

printf("%d\n", pArr[i]);



return 0;

}

输出结果:

请输入你要存放的元素个数:5

1 2 3 4 5

一维数组的内容是:

1

2

3

4

5

----------------------------------------------------------------------------

静态内存和动态内存的比较

静态内存是由系统自动分配,由系统自动释放

静态内存是在栈中分配的

动态内存是由程序员手动分配,手动释放

动态内存是在堆分配的

跨函数使用内存的问题

----------------------------------------------------------------------------

# include <stdio.h>





void f(int ** q){

int i = 5;

//*q 等价于p q 和**q都不等价于p

*q = &i;

}

int main(void){

int * p;



f(&p);  //访问完后释放内存

printf("%d\n", *p); //本语句语法没有问题, 但逻辑上有问题

//访问了不该访问的内存,f()函数结束后i的空间已经被释放

//静态变量,不能跨函数使用,当函数结束后变量不能被访问



return 0;

}

------------------------------------------------------------------------------

# include <stdio.h>

# include <malloc.h>





void f(int **q){

*q = (int*)malloc(sizeof(int)); //动态分配内存

//等价于 p = (int *)malloc(sizeof(int));

**q = 5;

}





int main(void){

int * p;

f(&p);

printf("%d\n", *p); //f()结束后,p指向的动态内存没有释放



return 0;

}

----------------------------------------------------------------------------------

c语言学习笔记(9)——指针的更多相关文章

  1. 《C语言学习笔记》指针数组及其应用

    C语言中,最灵活但又容易出错的莫过于指针了.而指针数组,是在C中很常见的一个应用.指针数组的意思是说,这个数组存储的所有对象都为指针.除了存储对象为指针,即一个地址外,其它操作和普通数组完全一样. # ...

  2. C语言学习笔记--数组指针和指针数组

    C 语言中的数组有自己特定的类型,数组的类型由元素类型和数组大小共同决定.(如 int array[5]类型为 int[5]) 1.定义数组类型 C 语言中通过 typedef 为数组类型重命名:ty ...

  3. 【C语言学习笔记】指针

    用来存放一个变量地址的变量就叫指针变量.指针变量也是有类型约束的,一般什么类型的指针指向什么类型的变量. 指针之所以叫变量,是因为它里面所存放的变量的地址也是不断变化的,指针是可以移动的. 定义格式: ...

  4. Go语言学习笔记(6)——指针

    指  针 指针: 存储另一个变量的内存地址的变量: Go语言的取地址符号也是& 1. 声明指针: var needle_name *type var b int = 10 var a *int ...

  5. C语言学习笔记--关于指针的一些小认知

    int main() { int i; char *str = "hu mian yuan"; int length = strlen(str); printf("str ...

  6. Go语言学习笔记九: 指针

    Go语言学习笔记九: 指针 指针的概念是当时学C语言时了解的.Go语言的指针感觉与C语言的没啥不同. 指针定义与使用 指针变量是保存内存地址的变量.其他变量保存的是数值,而指针变量保存的是内存地址.这 ...

  7. GO语言学习笔记(一)

    GO语言学习笔记 1.数组切片slice:可动态增长的数组 2.错误处理流程关键字:defer panic recover 3.变量的初始化:以下效果一样 `var a int = 10` `var ...

  8. Go语言学习笔记十: 结构体

    Go语言学习笔记十: 结构体 Go语言的结构体语法和C语言类似.而结构体这个概念就类似高级语言Java中的类. 结构体定义 结构体有两个关键字type和struct,中间夹着一个结构体名称.大括号里面 ...

  9. Go语言学习笔记七: 函数

    Go语言学习笔记七: 函数 Go语言有函数还有方法,神奇不.这有点像python了. 函数定义 func function_name( [parameter list] ) [return_types ...

  10. Go语言学习笔记四: 运算符

    Go语言学习笔记四: 运算符 这章知识好无聊呀,本来想跨过去,但没准有初学者要学,还是写写吧. 运算符种类 与你预期的一样,Go的特点就是啥都有,爱用哪个用哪个,所以市面上的运算符基本都有. 算术运算 ...

随机推荐

  1. keil出现一些库函数没有定义

  2. Vue.js组件的重要选项

    Vue.js组件的重要选项 实例化Vue对象一些很重要的选项,Vue的所有数据都是放在data里面的,Vue的参数是个对象,对象里面的字段叫做data,data里面也是对象,data也可以写作是thi ...

  3. android权限详细

    访问登记属性 android.permission.ACCESS_CHECKIN_PROPERTIES ,读取或写入登记check-in数据库属性表的权限 获取错略位置 android.permiss ...

  4. [HTML] Change an HTML5 input's placeholder color with CSS

    We will look at what CSS selectors to use to change an HTML5 inputs placeholder color. This can diff ...

  5. POJ 1833 生成排列

    题目链接:POJ 1833 /************************************ * author : Grant Yuan * time : 2014/10/19 16:38 ...

  6. MM常用的双关语(男士必读)

    我们还是当朋友好了 (其实你还是有多馀的利用价值)我想我真的不适合你(我根本就不喜欢你.)天气好冷喔,手都快结冰了 (快牵我的手吧,大木头!)我觉得我需要更多一点的空间 (我不太想看到你啦!)其实你人 ...

  7. QAtomicInt支持四种类型的操作,Relaxed、Acquired、Release、Ordered

    Memory Ordering   Background 很久很久很久以前,CPU忠厚老实,一条一条指令的执行我们给它的程序,规规矩矩的进行计算和内存的存取. 很久很久以前, CPU学会了Out-Of ...

  8. 【心情】bjdldrz

    如果我对勇士的记忆停留在73胜10负,

  9. Deepin系统更新apt-get源

    1.复制原文件备份sudo cp /etc/apt/source.list /etc/apt/source.list.bak2.编辑源列表文件sudo vim /etc/apt/source.list ...

  10. QT学习记录之理解信号槽机制

    作者:朱金灿 来源:http://blog.csdn.net/clever101 QT的事件机制采用的信号槽机制.所谓信号槽机制,简而言之就是将信号和信号处理函数绑定在一起,比如一个按钮被单击是一个信 ...