目录
1. 概念
指针就是地址 --- 内存单元的编号
指针也是一种数据类型 --- 这种数据类型专门用来处理地址这种数据
语法:
基类型 * 指针变量名
(1)基类型:就是结构体类型,表示该指针所指向的内存空间存放什么类型的数据
(2)* :表示此时定义的是一个 指针类型 的变量
(3)指针变量名:符合标识符命名规则
2. 指针变量初始化
如果指针变量没有初始化,此时是随机值。---- 野指针
初始化可以让指针变量有明确指向。
赋值:
int a = 10;
int *p;
p = &a; // p指向a,因为p中保存了a的地址
int *p = NULL; // NULL 0号地址---空指针
int *p,q; // p是指针类型,q是int型
int *p,*q // 此时表示定义了两个int*类型的变量p,q
2.1 被调修改主调
(1)指针作为函数参数
形参 --- 指针类型变量,用来接收实参
实参 --- 要修改谁就把谁的地址传过去 要保证空间有效
注:被调函数中必须要有 *p 运算
(2)值传递和地址传递
值传递 --- 只是实参数据赋值了形参
地址(指针)传递 --- 传的是地址 -- 可以实现被调修改主调
eg:实现两个数求和,通过参数带出来
#include<stdio.h>
void ADD(int a,int b,int *sum)
{
*sum = a+b;
}
int main(void)
{
int x=10;
int y=2;
int sum;
ADD(x,y,&sum);
printf("%d\n",sum);
return 0;
}
2.2 指针变量的引用
*p --- 表示访问p所指向的基类型的内存空间
(1)间接访问
(2)通过a访问 --- 直接访问
step1: 首先拿出p中地址,到内存中定位
step2: 偏移出sizeof(基类型)大小的一块空间
step3: 将偏移出的这块空间,当做一个基类型变量来看
3. 指针 + 一维整型数组
数组名就是数组首元素的地址。
数组名是个常量,不能做自增自减运算。
int *p = a; //p 指向了数组a。
a <=> &a[0]
void printArray(int *a,int len) // 数组作为函数参数,实参传数组名
3.1 指针的运算
p+1 加n 表示跳过n个基类型
p-1
p++
p--
不能运算p+q
p - q 表示差了多少个元素(基类型)必须是同一类型的指针
*(p+i)<=> a[ i ] <=>*(a+i)
4. 指针 + 一维字符型数组
char s[] = "hello";
char *p = s;
void Puts(char *s) // 指针型一维字符数组做函数参数
const 只读,就近原则,离谁近就修饰谁。
const int a; --- 此时a是一个只读的变量
const int *p = &a; ----- const限定是 基类型 ,表示不能通过 *p 的方式 修改基类型数据
int const *p = &a; ---- const限定是 基类型 ,表示不能通过 *p 的方式 修改基类型数据
int * const p = &a; ---- const限定是 指针变量p 表示将p限定位只读 ,p不能被修改
const int * const p = &a; ---- 基类型和指针变量 都被限定为只读
p = &b; 不能修改
*p = b; //不能修改
应用:
(1)如果 不想 通过*p方式改变基类型对应的数据
const int *p = &a;
int const *p = &a;
(2)如果 指针变量p 定义好后,不想再指向别的变量
int * const p = &a;
注意:
(1)形参设计为 const char * ,目的是为了防止操作函数中误操作
(2)可以提前发现问题。
4.1 指针 +字符串
字符串 --- 在c语言中是按照字符数组的形式存储 --- 字符串常量 --- 存储在字符串常量区
const char *p = "hello"; 表示 p指向了 字符串常量区中的 "hello",因为 是指向了字符串常量区 ,只能做读取操作,不能修改
下面给出了指针处理字符串实现:gets,puts,strlen,strcpy,strcmp的代码
#include<stdio.h>
// 输出函数
int Puts(const char *s)
{
if(s == NULL)
{
return -1;
}
while(*s != '\0')
{
putchar(*s++);
}
putchar('\n');
return 0;
}
// 输入函数
char *Gets(char *s)
{
char *ret = s;
while((*s = getchar())!='\n')
{
s++;
}
*s ='\0';
return ret;
}
// strlen实现函数
size_t Strlen(const char *s)
{
long int cnt = 0;
while(*s != '\0')
{
++s;
++cnt;
}
return cnt;
}
// strcpy函数实现
char *Strcpy(char *dest,const char *src)
{
char *ret = dest;
while(*src != '\0')
{
*dest++ = *src++;
}
*dest = '\0';
return ret;
}
char *Strncpy(char *dest,const char *src,size_t n)
{
char *ret = dest;
while( n && *src != '\0')
{
*dest++ = *src++;
--n;
}
while(n)
{
*dest = '\0';
--n;
}
return ret;
}
char *Strcat(char *dest,const char *src)
{
char *ret = dest;
while(*dest != '\0')
{
dest++;
}
while(*src != '\0')
{
*dest++ = *src++;
}
*dest = '\0';
return ret;
}
char *Strncat(char *dest,const char *src,size_t n)
{
char *ret = dest;
while(*dest != '\0')
{
dest++;
}
while(n && *src != '\0')
{
*dest++ = *src++;
--n;
}
*dest = '\0';
return ret;
}
int Strcmp(const char *s1,const char *s2)
{
while(*s1==*s2 && *s1!='\0' && *s2!='\0')
{
++s1;
++s2;
}
return *s1 - *s2;
}
int Strncmp(const char *s1,const char *s2,size_t n)
{
while(n>1 && *s1==*s2 && *s1!='\0' && *s2!='\0')
{
++s1;
++s2;
--n;
}
return *s1 - *s2;
}
void * --- 不是空指针,而是空类型的指针,也是万能指针,可以接收任意类型的指针
注意:如果用 空类型指针 进行 间接运算 必须 转换成 有明确类型的指针