C语言指针
C语言指针
一、函数的实际运行原理
? 函数在接受参数的时候,会重新开辟内存来进行计算。
二、指针
? 最牛逼:汇编语言:都是直接操作地址去访问内存单元里面等内容。
? C语言作为高级语言:提供通过地言:都是址去访问内存单元的内容。
1、什么叫做地址?
? 地址就是内存中对每一个字节的编号。
? 通常一个数据的地址指的是存放这个数据的地址段的首地址。
注意:1、一个程序在运行是会自动为变量开辟新的内存,地址会变。
? 2、在同一次运行过程中变量的地址是不会变的。
? 3、数据段,一个程序是在一个数据段中进行的。
&(取地址运算符):单目运算符,返回一个变量的地址
*(指针运算符):单目运算符,返回的是一个地址里面的变量的数据。
&和*具有相同的优先级,自右向左结合。
2、什么是指针?
指针就是地址,地址就是指针。
3、什么是指针变量?
存放地址的变量。
1、指针变量的声明:
数据类型 变量名; int p;
2、指针变量的赋值:
? A、在声明指针的时候赋值:int *p=&a;
? B、先声明,再赋值。 Int *p; p=&a;
? C、不允许把一个数赋值给指针变量:int *p; p=50000;(错误的)
3、指针变量的引用:
变量名;Int p; p=&a; *p=a;
#include <stdio.h> int main() { int a, b; int* p; //声明一个指针变量 a = 20; b = 25; p = &a; //把变量啊的地址赋予p 10000 printf("变量a的值为:%d\n", a); printf("变量b的值为:%d\n", b); printf("变量a的地址为:%d\n", &a); printf("变量b的地址为:%d\n", &b); printf("指针变量p的值为:%d\n", p); printf("指针变量p指向的变量的值为:%d\n", *p); return 0; }
#include <stdio.h> int main() { ? int a, b; ? int temp; ? a = 6; ? b = 3; ? temp = a; ? a = b; ? b = temp; ? printf("a=%d\nb=%d\n", a, b); return 0; }
#include <stdio.h> void Swap(int a1, int b1); int main() { ? int a, b; ? a = 6; ? b = 3; ? Swap(a, b); ? printf("a=%d\nb=%d\n", a, b); return 0; } void Swap(int a1, int b1) { ? int temp; ? temp = a1; ? a1 = b1; ? b1 = temp; }
#include <stdio.h> void Swap(int* pa1, int pb1); int main() { ? int a, b; ? int* pa,*pb; ? a = 6; ? b = 3; ? pa = &a; ? pb = &b; ? Swap(pa, pb); printf("a=%d\nb=%d\n", a, b); } void Swap(int* pa1, int* pb1) { ? int temp; ? temp = *pa1; // ? *pa1 = *pb1; ? *pb1 = temp; }
// x=x+y y=x-y #include <stdio.h> void Calc(int* pa1, int* pb1); int main() { ? int a = 6, b = 3; ? int* pa = &a, *pb = &b; ? Calc(pa, pb); ? printf("a=%d\nb=%d\n", a, b); } void Calc(int* pa1, int* pb1) { ? int temp; ? temp = *pa1; ? *pa1 = *pa1 + *pb1; ? *pb1 = temp - *pb1; }
最后一个:int a float b double c 运算 加减乘除 a+b c+c a-b b*c a/b
指针变量的运算:
(1)指针变量只可以做加减,不能做乘除,可以做关系运算
(2)加减法时,以指针指向的变量存储字节为单位。
Int a int *p; p=&a;2000 p+1=2004 4 Short p+1 2002 2 Char p+1 2001 1 Pa pb pc --> a *pa -->a *pb 的值实际上就是a的值 *pb也会变化。
# 三、指针与数组
&寻址运算符
*指针运算符
&寻址运算符与*****指针运算符具有相同的优先级,自右向左结合。
int a;
Int *p=&a;
*&a---->a
&*p---->p
int *p=&a;
1、指针的赋值
声明的时候:赋值int *p=&a;
先声明再赋值:int a; int *p; p=&a;
*p单独出现的时候是数据。
**int *p 前面带有数据类型。**
2 、一维数组和指针
2.1、一维数组地址。
一维数组和一维数组和指针
1、数组名就是数组的首地址。
? int a[10]; a就是首地址 int*p=a;
? 就是数组第一个元素的地址。
?
#include <stdio.h> int main() { int arr[5]; printf("%d\n", &arr[0]); return 0; }
定义一个指针,把一维数组的首地址&a[0]赋予这个指针ptr,就说ptr指向数组a[5]。一个数组的数组名就是这个数组的首地址。arr[5] &arr[0] == arr == ptr
2.2、对一维数组进行输入和输出。
A、指针不发生改变。
#include <stdio.h> int main() { ? //int arr[5]; ? //for (int i = 0; i < 5; i++) ? //{ ? // arr[i] = i + 1; ? //} //for (int i = 0; i < 5; i++) ? //{ ? // printf("arr[%d]=%d\n", i, arr[i]); ? //} ? int arr[5]; ? int* p = arr; // int *p=&arr[0]; ? for (int i = 0; i < 5; i++) //i 0-4 ? { ? //只要指针变量声明完之后 p就是地址 *p就是陪这个地址指向的变量。 ? *(p + i) = i + 1; //arr[0]--*p arr[1]--*(p+1) arr[2]--*(p+2) ? } ? for (int i = 0; i < 5; i++) ? { ? printf("arr[%d]=%d\n", i, *(p + i)); ? } }
星号*****只有在声明的是时候表示是指针,其他任何情况单独出现星号* 都表示指针运算符。
B、在对数组索引是,指针p发生改变,那么在打印之前必须把p重新指向数组的首地址。
int arr[5]; ? int* p = arr; // int *p=&arr[0]; /******************************** ? 1: *p -- arr[0] 1 ? 2: *(p+1) -- arr[1] 2 ? 3: *((p+1)+1) -- arr[2] 3 ? ********************************/ ? printf("赋值之前:%d\n", p); ? for (int i = 0; i< 5; i++) //i 0-4 ? { ? * p++ = i + 1; //能不能把一到5复制到数组 p是在发生变化的 ? //在一个表达式里面 p++ 就是先计算表达式的值 在给p+1 ? //++p 先给p+1 再计算表达式的值 ? } ? printf("赋值之后:%d\n", p); ? for (int i = 0; i< 5; i++) ? { ? printf("arr[%d]=%d\n", i, arr[i]); ? } ? p = &arr[0]; //把p重新指向数组的首地址 ? printf("打印之前:%d\n", p); ? for (int i = 0; i< 5; i++) ? { ? printf("arr[%d]=%d\n", i, * p++); ? } ? printf("打印之后:%d\n", p);
建议:遇见指针:1、这个指针的指向类型? 2、这个指针指向哪里? 3、指针自己的类型?
2.3、二维数组和指针
2.3.1、二维数组的地址
首地址:
&a[0][0] a[0] &a[0] a &a
行地址:
1、第0行的地址就是首地址
2、第1行 &a[1][0] a[1] &a[1] a+1
3、第2行 &a[2][0] a[2] &a[2] a+2
4、第i行 &a[i][0] a[i] &a[i] a+i
蓝色的加法就加一维数组的字节数 橙色的加法加数据类型的字节数
通过行地址去找到n行m列的元素。
&a[n][m] a[n]+m (关键是要搞清楚 以一维数组老做判断 还是以整体的二维数组来进行判断 )
//n行m列的元素
*(a[n]+m)
((a+n)+m) //a+n a[n] *(a+n) a[n]+m
? 二维数组和指针
? int a[3][5]
? 行地址:a+0(&a[0]) a+1(a[1]) a+2(&a[2])
? 列地址:a[0]+0 a[0]+1 a[0]+2 a[0]+3 a[0]+4
? 注意:利用指针引用二维数组关键记住:*(a+i) a[i]等价一维数组和指针
? 1、数组名就是数组的首地址。
? int a[10]; a就是首地址 int*p=a;
四、字符串与指针
字符串指针指向一块内存,存放字符串。
1、怎样去访问字符串?
a、用字符数组去一个一个去访问。
? b、用指针去访问(可以省略掉数组的定义)
2、字符串指针的定义和赋值。
char *p = "Hello"; ? char *p; ? p = "Hello";
3、字符串指针的简单运用
#include <stdio.h> int main() { ? char a[6] = "Hello"; //1 ? char *p = a; ? //char *p = "Hello"; //2 ? //char *p; //3 ? //p = "Hello"; ? printf("%s\n", p); //%s 挨着打印地址里面的字符 遇到'\0' ? printf("%s\n", a); ? printf("%c\n", *p); //'\0' %c ? printf("%d\n", *p); ? return 0; }
? 程序 标识符 关键字 运算符 每一个符号出现的时候 这个符号是什么。
? //%d %c %e 打印的都是一个变量里面的内容 char 1 int 4 float 4
? //%s 打印连续内存里面的内容 遇到‘\0‘结束
4、连接两个字符串
#include <stdio.h> int main() { ? //字符数组的一个特点 定义数组的时候,内存开辟的大小是确定的。 ? char a[100] = "Hello"; ? char b[100] = "World"; ? char *p1 = a, *p2 = b; ? printf("移动前:%d\n", p1); ? for (; *p1 != '\0'; p1++); ? printf("移动后:%d\n", p1); ? for (; *p2 != '\0'; p1++, p2++) ? *p1 = *p2; ? printf("%s\n", a); ? return 0; }
5、字符串数组
字符数组
char a[6] = "Hello";
字符串数组
char name[6][15] =
{"Faker","Gragon",
"Liangren","Banhave",
"Jack",
"Hualuo"};
字符串指针数组 里面的每一个元素都是指针
char *pName[] =
? {
? "Faker", //6
? "Gragon", //
? "Liangren",//9
? "Banhave",
? "Jack", //5
? "Hualuo"
? };
字符串指针数组的输入输出
include <stdio.h> int main() { // 字符数组 char a[6] = "Hello"; // 字符串数组 char name[6][15] = { "Faker", 6 "Gragon", "Liangren",9 "Banhave", "Jack", 5 "Hualuo" }; printf("%d\n", &name[0]); // 15 printf("%d\n", &name[1]); //15 }
6、字符串指针数组 里面的每一个元素都是指针
char *pName[] = ? { ? "Faker", //6 ? "Gragon", // ? "Liangren",//9 ? "Banhave", ? "Jack", //5 ? "Hualuo" ? }; ? printf("%d\n", pName); //地址 ? printf("%d\n", pName+1); //p1+1 ? for (int i = 0; i < 6; i++) ? { ? printf("%s\n", *(pName + i)); ? } ? return 0; }
指针数组 所有元素都是指针
数组指针 一个指针 指向一个数组 元素不一定 int char float
函数和指针: 指针跟函数 二级指针与函数 数组和函数 二维数组和函数