1.引入
int a;
a=100;//把100存放的a对应的存储单元中
b=a; //取变量a的值
访问:
存储:到对应的地址单元中去存储值 a=100(write)
取值:从对应的地址单元中去取 b=a (read)
访问方式:
直接访问:通过变量名去访问变量
间接访问:通过地址去访问变量
======>指针
2.指针的概念
地址:定义某个变量之后,编译器会给每个变量分配一段空间,每一个字节的空间都对应有一个编号,这个编号就是地址
☆指针:指针就是地址
指针变量:存储指针的变量、存储地址的变量
3.指针变量:
定义指针变量:
指向数据的类型 *指针变量名
☆ 指向:int a; char b;
int *p; char *p1;
p=&a;//p是指向变量a的 p1=&b;
sizeof(p)=4; sizeof(p1)=4;
存储了谁的地址,就说它指向谁
”Int 类型说明符“:决定它要指向的数据的类型
int a;
1.int *p=&a;
2.int *p;
p=&a;
*p:表示的是p指向的变量a
4.如何获取地址
1.通过&
&对象名:表示该对象的地址
对象:变量,数组元素 Int a[0] (例:a[0]是素组元素) int a[3][4](例如:a[0][1])
2.有些对象的名字本身就是地址
如:数组名、函数名
5.如何通过指针访问变量(*) 指向运算符
*指向运算符:
*地址 <====>该地址对应的变量
*&a <====>a这个变量
☆*指针变量<======>该指针变量指向的变量
int a;
int *p;
p=&a;
*p 表示:a这个变量
ex.写一个函数,实现2个整型变量交换值
6.指针与函数参数
如果要在一个函数内部操作“别的函数”的变量,
但是“别的函数”那个变量的作用域不可见,
只能通过地址来访问它。
7.数组与指针
☆1.指针加减:加减它所指向数据类型的长度
2.如果定义一个指针变量指向数组a
int a[10]={1,2,3,4,5,6,7,8,9,10};
int *p=&a[0];
a.访问a[0]的方式:
1).a[0] *a
2).p[0] *p
3)*&a[0]
b).访问a[1]的方式:
1).a[1] *(a+1) (*a+1):a指向的变量值加1
2).p[1] *(p+1)
补充:a中存储的是&a[0];
| |
a是指向a[0]的;
| |
*a表示的就是a[0]
ex.使用指针的方式来遍历一个数组
3.数组名与指针
数组名可以看做是一个指针常量
int const a=123;//a的存储内容不可以通过变量名的方式来改变,但是可以通过指针的方式来改变
错误代码示范及结果:
#include<stdio.h>
int main()
{
int const a=123;
printf("%d",a);
a++;
printf("%d",a);
return 0;
}
输出结果:
caogao.c: In function ‘main’:
caogao.c:7:2: error: increment of read-only variable ‘a’
a++;
^
正确代码示范及结果:
#include<stdio.h>
int main()
{
int const a=123;
printf("%d\n",a);
int *p=(int *) &a; --- --- ---//特别注意:使用 "int *p=&a;" 是错误的!!!!!!!!!!
*p=5;
printf("%d\n",*p);
return 0;
}
输出结果:
123
5
1)指针常量
int * const p;
p的指向不可改变,
但是p指向的内容是可以改变的
错误代码示范及结果:
#include<stdio.h>
int main()
{
int a=5,b=6;
int * const p=&a;
printf("%d\n",*p);
p=&b;
printf("%d\n",*p);
return 0;
}
输出结果:
caogao.c: In function ‘main’:
caogao.c:7:2: error: assignment of read-only variable ‘p’
p=&b;
^
正确代码示范及结果:
#include<stdio.h>
int main()
{
int a=5,b=6;
int * const p=&a;
printf("%d\n",*p);
//p=&b; --- --- ---把" p=&b;" 注释掉,不能改变p的指向!!!!!
printf("%d\n",*p);
return 0;
}
输出结果:
5
5
错误代码示范及结果:
#include<stdio.h>
int main()
{
int a=5,b=6;
int * const p=&a; --- ---//p指向a;
printf("%d\n",*p);
*p++; --- --- ---//*p不可改变 ?
printf("%d\n",*p);
return 0;
}
输出结果:
caogao.c: In function ‘main’:
caogao.c:7:2: error: increment of read-only variable ‘p’
*p++;
^
错误代码示范及结果:
#include<stdio.h>
int main()
{
int a=5,b=6;
int * const p=&a; --- ---//p指向a;
printf("%d\n",*p);
p++; --- --- ---//p++即为(p=p+1);p将指向(p+1);但是p的指向不可变; 所以错误; ?
printf("%d\n",*p);
return 0;
}
输出结果:
caogao.c: In function ‘main’:
caogao.c:7:2: error: increment of read-only variable ‘p’
p++;
^
正确代码示范及结果:
#include<stdio.h>
int main()
{
int a=5,b=6;
int * const p=&a; --- ---//p指向a;
printf("%d\n",*p);
a++; --- --- ---//p的内容是a,a可变;
printf("%d\n",*p);
return 0;
}
输出结果:
5
6
个人总结:指针常量格式为: int * const p;
使用格式为: int a;
int * const p=&a; ------- p指向a;
在后面的程序中: 1.用 p 进行运算是 错误的,会改变p的指向!!! 比如 : p++; p=5; p=p1;.....
2.用 *p 进行运算是 错误的, 会???? 比如: *p++; *p=5; *p=*p1;....
3.用 a 进行运算是 正确的,会改变p的内容!!! 比如: a++; a=5; a=b;.....
2)常量指针
int const *p;
const int *p;
p的指向是可以改变的
但是p指向的内容不可改变
错误代码示范及结果:
#include<stdio.h>
int main()
{
int a=40,b=6;
int const *p=&a;
printf("%d\n",*p);
*p=50; --- --- //*p 是指取 p 指向的东西里面的内容,即*p是一个内容,不可改变!!!!!
printf("%d\n",*p);
return 0;
}
输出结果:
caogao.c: In function ‘main’:
caogao.c:7:2: error: assignment of read-only location ‘*p’
*p=50;
^
错误代码示范及结果:
#include<stdio.h>
int main()
{
int a=40,b=6;
int const *p=&a;
printf("%d\n",*p);
*p=b; --- ---- // *p 是指取 p 指向的东西里面的内容,即*p是一个内容,不可改变!!!!!
printf("%d\n",*p);
return 0;
}
输出结果:
caogao.2.c: In function ‘main’:
caogao.2.c:7:2: error: assignment of read-only location ‘*p’
*p=b;
^
正确代码示范及结果:
#include<stdio.h>
int main()
{
int a=40,b=6;
int const *p=&a;
printf("%d\n",*p);
a=50; --- --- // p 指向了 a 的地址,即 *p 指向 a 的内容; a 的内容自己改变了,但是并没有通过 *p;
printf("%d\n",a);
return 0;
}
输出结果:
40
50
正确代码示范及结果:
#include<stdio.h>
int main()
{
int a=40,b=6;
int const *p=&a; --- --- // p 指向了 a 的地址,即 *p 指向 a 的内容;
printf("%d\n",*p);
p=&b; --- --- ---//现在 p 重新指向了 b 的地址,但是没有使用 *p ;?????????
printf("%d\n",*p);
return 0;
}
输出结果:
40
6
错误代码示范及结果:
#include<stdio.h>
int main()
{
int a=40,b=6;
int const *p=&a;
printf("%d\n",*p);
p=50; --- --- --//不可以把一个常量赋值给一个地址;
printf("%d\n",*p);
return 0;
}
输出结果:
caogao.c: In function ‘main’:
caogao.c:7:3: warning: assignment makes pointer from integer without a cast [enabled by default]
p=50;
^
个人总结:常量指针格式:int const *p; 或 const int *p;
注意: int和const谁在前面都一样,不影响语义;所以二者等价;
*p 是指取 p 指向的东西里面的内容,即*p是一个内容,不可改变!!!!!
p 本身是一个变量,里面存放的是 一个地址 ,在后面的程序中也可以再存放别的地址;
3)const int *const p;
4.指针数组与数组指针
指针数组 int *a[10]//表示每一个元素的数据类型都是int*
数组指针 int(*a)[10]//a是一个指针,指向int[10]
int a[10]---->a中存储的是&a[0] a的指向的数据类型应该是int a的类型是int*
&a ---->a中存储的是&a &a指向的数据类型应该是a的类型(int[10])
int (*p)[10]----> p的指向的数据类型应该是int[10] p的类型应该是 int[10] *
p=&a;//p=&int[10] a;
5.指针与二维数组
一位数组:
int a[10];
int** ------> int* ------ > int //定义时加*号往地址方向走
&a--------->a ------->a[0]
int[10]* int[10] int
====================================
a+1 &a[1]
*(a+1) a[1]的值
*(*(&a+1)-1) a[9]的值 //使用指针变量时加*表示往值的方向走
&a+1 加了40个字节
===========================
二维数组:
int a[3][4] 数据类型 指向/存储的地址
a int[3][4] &a[0]
&a[0] int[4]* &a[0]
a[0] int [4] &a[0][0]
&a[0][0] int * &a[0][0]
================================================
a+1 &a[1]
&a[1] &a[1]
&a &a
&a+1 加了48个字节
=================================================
a[1]+2 &a[1][2]
&a[1][2] &a[1][2]
*(a[1]+2) 表示a[1][2]的值
*(*(a+1)+2) a[1][2]的值
a[1][2] a[1][2]的值
==================================================
8.字符串与指针
在C语言中,没有任何类型表示字符串
""字符串后面自动添加\0
"123"
只需要一个字符指针来存储字符的首地址,便可以找到整个字符串
char *s="1237";//把"1237"的首地址存储到指针变量s中
字符串存储在.rodata(只读数据)区域的
char *s="123456";
s="789"//指向可以改变
s[0]='p';//error 内容不可改变
char s[10];
s="123445";//指向被改变 错误
s[0]='2';//内容可被改变
char *gets(char *s);
功能:从屏幕上得到一个字符串
char *s:字符数组首地址,字符指针变量名,
把得到的字符串保存到s指向的地址中
返回值:返回得到字符串的首地址
int puts(const char *s);
功能:把字符串输出到屏幕上
const char *s:你要输出字符串的首地址
返回值:成功返回被输出字符的个数,失败返回-1
#include <string.h>
char *strcpy(char *dest, const char *src);
功能:把src地址中的字符串复制到dest中
src:你要拷贝的字符串首地址
dest:你要复制到的地址
返回值:返回dest字符串的首地址
char *strncpy(char *dest, const char *src, size_t n);
功能:把src地址中的字符串拷贝n个到dest中
src:你要拷贝的字符串首地址
dest:你要复制到的地址
n: 你要拷贝的字节个数
返回值:返回dest字符串的首地址
#include <string.h>
#include <string.h>
int strcmp(const char *s1, const char *s2);
功能:比较s1与s2的字符串大小(把s2与s1中的每个字符逐个比较,直到有个字符串为\0为止,或者2个字符不一致)
返回值:如果s1==s2 返回值为0
如果s1>s2 返回值为 1
如果s1<s2 返回值为-1
int strncmp(const char *s1, const char *s2, size_t n);
功能:比较s1与s2的字符串大小的前n个
其他与strcmp相同
#include <string.h>
char *strcat(char *dest, const char *src);
功能:把src的字符串追加到dest中(从dest的第一个'\0'开始追加)//char a[20]={0};
dest:你要追加到的字符串首地址
src:源字符串首地址
返回值:dest字符串的首地址
char *strncat(char *dest, const char *src, size_t n);
功能:把src的字符串追加到dest中(从dest的第一个'\0'开始追加)//char a[20]={0};
dest:你要追加到的字符串首地址
src:源字符串首地址
n:要追加的字符个数
返回值:dest字符串的首地址
ex。给3个字符串排序
9.指针函数与函数指针
int swap(int a,int b);
指针函数:int *swap(int a,int b);//swap是一个函数,只是返回值是指针
函数指针:int (*swap)(int a,int b)//swap是一个指针,指向int(int,int)类型的函数
定义:返回值类型 (*函数指针名)(参数列表)
参数列表:只要需要对应的形参的数据类型
例:int (*p)(int ,int );
赋值: a)p=&函数名;
b)p=函数名;
使用:(*函数指针名)(实参列表)
(*p)(1,2);
10.多级指针
int ***---->int** ---->int *---> int
11.动态分配内存空间
void *malloc(size_t size);
功能:动态分配内存空间
size:分配的字节数大小
返回值:分配空间的首地址
例子: int a=10;
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int a=10;
int *s=&a;//int 我要 到它指向的地址中读4个字节的内容
printf("%d",*s);
char *s="1234";
s=(char *)malloc(10);
strcpy(s,"4546");
printf("%s",s);
return 0;
}
void *calloc(size_t nmemb, size_t size);
功能:动态分配内存空间,并且会把分配的空间初始化成0
nmemb:分配多少块
size:每个块分配多少个字节
返回值:分配空间的首地址,
void *realloc(void *ptr, size_t size);
功能:增加分配ptr指向的地址空间
ptr :指向你要增加的空间首地址
size:增加的字节数
12.main参数
int main(int argc,char **argv)
{
printf("%d\n",argc);//argc表示运行参数的个数(当输入 ./a.out 123 3242 324 4325时,argc=5)
printf("%s\n",argv[1]);//表示运行参数的第一个字符串 123
return 0;
}
ex.使用运行参数的形式,把数字字符串 转换成 一个数
补充:
char *s=“1234”;
保存多个字符串:
char *s[10] // 可以存储10个字符串,每个字符串的字符是char *
单独输出一个字符串:printf("%s",s[0]);
char s[10][20];//可以存储10个字符串,每个字符串 char [20]
单独输出一个字符串:
printf(“%s”,s[0]);