C language learning - pointers

1. Pointers and pointer variables and definitions, use
1) What is a pointer:
pointer is an address ; (for example: int *p,a; p=&a, it can be said that p points to variable a, or p is a pointer to variable a)
2) What is a pointer variable:
pointer variables are used to storage address . (The meaning of defining the pointer is to access the memory unit through the pointer. At the same time, because the array or function is stored continuously, the first address of the array or function can be obtained by accessing the pointer variable through the pointer. In C language, a data type or Structures tend to occupy contiguous memory units)
3) Supplement:
One byte occupies one address, two bytes occupy two, and so on.
4) Example:
int *p,z; (the definition of a pointer variable, which can be Define multiple at the same time , multiple spaces can be added between * and the variable name, the pointer variable itself has no data type, and its data type here is the data type pointing to the memory unit it refers to )
p=&z; (The assignment of pointer variables can also be done like this: int *p=&a, or two pointers of the same type can be assigned to each other, such as: int *p, *z, a; p=&a; z=p
*p=4;
printf("%d", *p ) {If instead of *p, use p, the output is the address }
and: The output of the character pointer that appears later to the content is the direct output of the pointer variable name, that is, the pointer variable name is directly behind
5) Notes on pointer assignment:
In principle, a pointer can only point to variables of the same type. If the type of the pointer on the right is different from the one on the left when assigning a value to the pointer, then the 强制转换,将 右边的转换为左边
赋值语句中,被赋值的指针变量前不能有*,即:事先定义了指针变量p,在 赋值语句中出*p=&a是错误的。
在标准C下,不能用auto型变量来给static型指针赋值。
6)零指针与空类型指针
a. int *p=NULL与int *p=0 意思一样都是指 零指针
b. 空类型指针是指不知道指针指向什么类型,也可以是任意类型,所以在 使用时候需要强制转换
7)指针变量的引用:
*是间接引用运算符,是单目运算符,优先级与++,--相同,具有右结合性,同时需要注意的是a++与(*p)++意思一样,*p++与*(p++)意思一样都是地址++
8)注意:
指针变量需先定义后赋值,赋值后才能使用,没赋值使用是野指针,容易导致系统崩溃
指针变量也是变量,也需要占用内存单元,但是不同类型的 指针变量所占的内存单元都是一样的,取决于编译环境。


2.指针与地址运算:
1)指针变量的加减运算:
指针是地址,是一种无符号整数, 不能像整数那样参与乘法与除法,而指针的加减法并不是简单的加减,而是: p+(-)n= ADDR +(-) n*sizeof*(数据类型) {ADDR是当前p的地址}
两个指针相加没有任何意义,但是相减则可以表示两指针之间所相差的内存单元数或者元素的个数

3.指针与数组
1)数组指针:数组的指针其实就是数组在内存中的起始地址(数组变量名)。
2)引用:int a[10];
p=a或者&a[0]
3)注意: a+k等价于p+k,&a[k],即都是a[k]的地址
a[k]=*(a+k)=*(p+k)= p[k]
p+1指向数组的下一个元素而不是简单地使指针变量p的值+1,其实际变化为:p+1*sizeof(数据类型)


4)利用指针访问多维数组
a.利用一般指针变量访问多维数组(数组数据单元在内存中的存放顺序是按行进行的)
引用格式:*(p+i*)
三角号划重点!
b.行指针的定义:
数据类型 (*行指针变量名)[常量表达式]
说明:
行指针变量名和*号一定要用小括号括起来;
常量表达式规定了二维数组第二维的大小,它是不可忽略的;
数据类型符号则代表行指针所指一维数组的元素类型
c.通过行指针引用二维数组a的元素形式:
p [i][j]; *(p[i]+j) ; *((p+i)+j); (*(p+i))[j]
d.对二维数组行指针变量的赋值一般形式为:
二维数组名+整型常数n 例如:p=a+1;
&二维数组名[整型常量],例如:p=&a[0]

5)指针数组(存储指针的数组,也可以说是存储地址的数组)
a.引用格式:数据类型 *变量名[常量表达式]
例如: char a[3]; char *p[3]; p[0]=&a[0]; p[1]=&a[1]; p[2]=&a[2];
b.指针数组和二维数组的行指针变量的对比

6)指针与字符串
a.定义:字符串本身就是以'\0'结尾的字符型数组,字符串 在内存中的地址(即第一个地址)称为字符
串的指针
b.程序中的定义及赋值
char *字符指针变量名=字符串常量
char *字符指针变量名;
字符指针变量名=字符串常量
例如:
char *pstr=“I am a big man”
或者 char *pstr; pstr=“I am a big man”
注:上述的结果是将字符串的首地址赋值给字符串指针变量
c.字符串的引用
逐个引用:
整体引用:
系统首先输出pstr指向第一个字符,然后pstr自动加1,使之指向下一个字符,知道遇到字符串结束标志。

d.字符指针变量与字符数组之间的比较
1)存储内容不同
字符指针变量存储的是地址,而数组存储的是字符串本身
2)赋值方式不同
字符指针变量可以对指针变量名直接赋值,而数组的变量名是地址,是个常量,故不可以直接赋值
例如:char *pointer ,pointer="This is an example"
char carray[20]="This is an example."

e.字符指针变量使用注意:
当字符指针指向字符串时,除了可以被赋值之外,与包含字符串的字符数组没有区别,其次字符指针变量如果不指向一个字符数组或其他有效内存,也就是没有赋值时,不能使用,否则出错



7)指针与动态内存分配
a. 静态内存分配
当程序中定义变量或数组以后,系统就会给变量或数组按照其数据类型及大小来分配相应的内存单元。

b.动态内存分配
动态内存分配是指在程序运行过程中,根据程序的实际需要来分配一块大小合适的连续的内存单元,动态内存的分配需要有一个指针变量记录内存的起始地址

c.malloc()函数
函数malloc()用来分配若干个字节的内存空间,返回一个指向该区域的存储区地址的指针,如果系统不能提供足够的内存单元函数将返回空指针NULL,函数原型:
void *malloc(unsigned int size){size是分配内存大小,以字节为空间}
注意:利用该函数如果分配不成功,那么返回值是null空指针
如果成功,那么返回值则是指向任何类型的内存块的首地址
关于malloc使用的注意点:
(1)malloc前面必须加上一个指针类型转换符,因为malloc函数返回的是个任意类型的指针,它一般与左边的指针类型一致
(2)malloc所带的参数是内存字节数,一般形式为:分配数量*sizeof(内存单元类型)
(3)malloc可能返回一个NULL,所以一般调用该函数,其后面都要接一个判断语句,判断是否分配成功

d.calloc()函数
该函数用于非 若干个同一类型的数据分配连续存储空间,其中每个数据项的长度单位为字节,通过调用该函数所分配的存储单元,系统将其自动置为初值0,函数原型:
void *calloc(unsigned num,unsigned size)
(num:表示向系统申请的 内存空间的数量,size:表示申请的 每个内存空间的字节数)
例如:pscore=(int*)calloc(n,sizeof(int))
上述相当于:向系统申请了 一个一维数组,n为数组大小,sizeof(int)为数组元素数据类型
注意:调用这个函数一样需要在其后面判断是否分配成功

e.realloc()函数
该函数用于改变原来分配的内存空间大小,函数原型:
void *realloc(void *p,unsigned int size)
功能是将指针p所指向的存储空间的大小改为size个字节,如果分配内存失败,就返回NULL,如果成功,将返回存储空间的首地址,该首地址与原来分配的首地址 不一定相同


f.动态内存释放
在用完动态内存之后就要释放内存,一定要坚持:“好借好还,再借不难”
格式:void free(void *block)
一般malloc calloc realloc都要和free函数成对出现
且他们的头文件为stdlib.h或者malloc.h或者alloc.h

8)多级指针
a.二级指针的定义与引用
[存储类型] 数据类型 **变量名
定义格式说明:
存储类型是指二级指针变量本身的存储类型
数据类型符可以是任何一种有效的数据类型表示符,是指针变量 所指向的最终目标变量的数据类型
*号的个数表示指针的级数
例如:int a=3
int *p1;
int **p2;
p1=&a;
p2=&p1;
**p2=3;

9)指针作为函数参数
a.引入:参数的几种传递方式:
(1)若传递的是值,则被调函数的执行不会影响调用函数的实参
(2)若传递的是地址,那么在被调用函数中就可以对该地址所对应的内存单元进行引用,既可以读取该内存单元的值,也可以对该内存单元的值进行修改, 要实现地址调用,就必须用到指针型参数



10)指针作为函数返回值——指针函数
a.定义格式:
函数类型 *函数名 ([形参1,形参2,形参3]...)
b.注意:如果一个函数返回一个指针,请注意, 不能返回auto型局部变量的地址,但可以返回static型变量地址,因为局部变量用完就消失
需要把握原则:返回的指针所对应的内存空间不能因为该指针函数的返回而被释放掉
c.返回的指针通常有:
函数中 动态分配的内存的首地址
函数中的 静态变量或全局变量所对应的存储单元的首地址
通过指针形参所获得的实参的有效地址

10)指向函数的指针——函数指针
























Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325805410&siteId=291194637