前言:
现在我们对“c语言中使用变量必须先什么后什么”大概比较珍视,我们都需要知道一些“c语言中使用变量必须先什么后什么”的相关资讯。那么小编也在网络上网罗了一些对于“c语言中使用变量必须先什么后什么””的相关知识,希望我们能喜欢,看官们快快来了解一下吧!C语言最强,最容易出错的功能
内存是由按顺序编号的一系列存储单元组成的,在内存中,每个存储单元都由难一的地址,通过地址可以方便地在内存单元中存储信息。
#include<stdio.h>void main() { printf("%p\n", main);//首地址 int num; num = 8; printf("%p", &num); getchar();}
函数就是代码,变量就是数据
CPU执行流程
程序要进行的操作对应的代码被装载到代码区。
全局和静态数据等装载到数据区
开辟堆栈,供临变量等使用
指针:一个变量的地址
指针变量:专门存放变量地址的变量
void main() { int num; num = 8; printf("%p", &num); printf("%d", num); getchar();}
可以手动在内存中编辑这个值
#include<stdio.h>void main() { int num; num = 8; printf("%p", &num); printf("%d\n", num); printf("%d", *(&num));//这里就是通过*去读取对应地址的内容 getchar();}&与*的关系
#include<stdio.h>void main() { int num = 100; int* p = # printf("%d,%d\n", num, *p); printf("%p,%p", p, &num);}
#include<stdio.h>void main() { int num = 100; int* p = # //一个指向int类型的指针变量,可以存一个int的变量 printf("%d,%d\n", num, *p); printf("%p,%p\n", p, &num); *p = 200;//这个对应修改了num printf("%d,%d", *p, num);}
*p等价于num,p等价与&num
&取地址,*指地址中的内容
为什么要给*加上一个类型,这里是可以确定要从内存中什么地方读多长,int是4个字节,double就是8个了,char只是一个了。
#include<stdio.h>void main() { int num1 = 100; int num2 = 200; int* p = &num1; *p = 99; printf("%d\n", num1); p = &num2;//修改了地址,将p的地址修改成了num2的地址 *p = 199; printf("%d,%d", num1, num2);}
传入地址,指针可以在函数内修改一个外部变量的值
#include<stdio.h>void edit(int *x) { *x = 99;}void main() { int x = 100; edit(&x); printf("%d", x);}
一个修改内存的例子
可以使用 __declspec(dllexport) 关键字从 DLL 中导出数据、函数、类或类成员函数。
#include<stdio.h>#include<Windows.h>void main() { int x = 0; printf("%p\n", &x); while (1) { x++; Sleep(5000); printf("%d\n", x); }}
将下面Dll注入到上面程序
#include<stdio.h>#include<stdlib.h>#include<Windows.h>//一个程序,不可以随便读取另外一个程序的内存//window内部,进程之间不能直接访问_declspec(dllexport) void DllMain() { int* p =(int *) 0x000000D95850F5C4; *p = 800; MessageBoxA(NULL,"a","d",MB_ICONERROR|MB_YESNOCANCEL);}指针与内存
#include<stdio.h>#include<Windows.h>void main() { int num = 100; int* p; p = num;//这里一定想明白,p是一个地址,这样编译不会出错,但运行会出错 p = # printf("%d", *p);}
修改一下,观察内存中的变化
void main() { int num = 100; int* p; p = num;//这里一定想明白,p是一个地址,这样编译不会出错,但运行会出错 p = # printf("%p", &p);}
*p对应的是数值,&p是地址
指针的大小
void main() { int* p1; double* p2; char* p3; printf("%d,%d,%d", sizeof(p1), sizeof(p2), sizeof(p3)); getchar();}
这里对应64位机器,输出都是8位,这里能想明白吗?因为他是地址,所以大小固定。
所谓指针,指的是“储存的内容是地址的量”,两个要点:一、指针是个量,对应着一块内存区域,二,指针存储的信息是某个内存单元的地址。
指针变量声明
C 语言规定所有变量在使用前必须先定义,指定其类型,并按此分配内存单元。指针变量不同于整型变量和其他类型的变量,它是专门用来存放地址的,所以必须将它定义为“指针类型”。
基类型 *指针变量名;
int *i;float *j;
“*” 表示该变量的类型为指针类型。指针变量名为 i 和 j,而不是 *i 和 *j。
void main() { int* p1, p2, p3; printf("%d,%d,%d", sizeof(p1), sizeof(p2), sizeof(p3));}
看看这个,p1对应8,而p2,p3是4,这是因为64位下指针固定就是8,另外两个并不是指针。
void main() { int* p = NULL;//空,不是0,不指向任何变量 if (p == NULL) { printf("p is null"); } else { printf("ps not is null"); }}间接与直接调用
void main() { int num = 100; printf("%d,%p\n", num, &num);//直接 *(&num) = 99;//根据地址取值,间接 printf("%d,%p\n", num, &num); int* p = #//p 是指针 *p = 98;//赋值,这里*p等价于num printf("%d,%p", *p, p);}
直接访问:按变量地址存取变量值
间接访问:通过存放变量地址的变量去访问变量
理解一下scanf输入指针地址
void main() { int num1; scanf_s("%d", &num1); printf("%d,%p\n", num1, &num1); int num2; int* p=NULL; scanf_s("%p", &p);//这里输入一个地址,将&num1的地址给它 printf("%d,%p", *p, p);}不修改变量值,通过指针交将数据
#include<stdio.h>#include<Windows.h>void main() { int a, b; int* pa, * pb; a = 1000; b = 500; if (a > b) { pa = &b; pb = &a; } else { pa = &a; pb = &b; } printf("%d,%d", *pa, *pb);}指针与函数参数
#include<stdio.h>#include<Windows.h>void change(int* address) { *address = 5;//&取出地址,*根据地址找值 printf("change:%d,%p\n",*address,&address);}void main() { int num = 10; printf("main:%d,%p\n", num, &num); change(&num); printf("main:%d,%p\n", num, &num);}
函数调用,改变原数据,传地址,可以改变,传数据,无法改变。
数组作为参数,传递的是指针
//数组作为参数,传递的是指针//在32位系统(即x86)中,指针的大小为4字节。//在64位系统(即x64)中,指针的大小为8字节。void show(int a[5]) { printf("show:%d\n", sizeof(a));}void main() { int a[10] = { 1,2,3,4,5 }; printf("main:%d\n", sizeof(a)); show(a);}
这里修改就是指针
void show(int a[5]) { printf("show:%d\n", sizeof(a)); for (int i = 0; i < 5; i++) { a[i] = i + 2; }}void main() { int a[10] = { 1,2,3,4,5 }; printf("main:%d\n", sizeof(a)); show(a); for (int i = 0; i < 5; i++) { printf("a[%d]=%d\n", i, a[i]); }}指向指针的指针基础
指针变量也是变量,占据一定的内存空间有地址,因此可以用一个指针指向它,这称为指向指针的指针,或二级指针。
有一个 int 类型的变量 a,p1是指向 a 的指针变量,p2 又是指向 p1 的指针变量,它们的关系如下图所示:
#include<stdio.h>#include<Windows.h>void main() { int a = 100; int* p1 = &a; int** p2 = &p1; printf("%p,%p", p1, p2);}
指针类型决定从地址开始取多少位
void main() { double d1 = 98.23; double* p = &d1; double** p1 = &p; //88 f8 2f 5a ef printf("%f,%p,%p", *p,p1,p);}
在x64下有一个错误是看不出来的,在32位,或c++下会出错
这里&p是一个地址,将它放入一个double *中是不对的,数据长度不同。
&p对应的就double**
void change(double** p) { **p = 88.2; printf("change:%f,%p\n", **p,*p);}void main() { double d1 = 98.23; double* p = &d1; change(&p); printf("main:%f,%p\n", *p,p);}
这里比较明显看到**p就是一个二级指针,它指向的就是*p的地址。
改变外部变量,如果是一个数据,传递数据的地址(指针),如果是一个指针,传递指针的地址。
注入二级指针
目标代码
#include<stdio.h>#include<Windows.h>void main() { int num = 100; char level1 = 'A', level2 = 'B', level3 = 'C'; char* level = &level1; //这里需要知道*level的地址 printf("%p,%p,%p,%p,%p\n", &num, &level,&level1,&level2,&level3); while (1) { printf("num=%d,level=%c\n", num, *level); Sleep(3000); }}
注入代码
#include<stdio.h>#include<windows.h>_declspec(dllexport) void DllMain() { int* p = (int*)0x00000058F24FF544; *p = 9999; char** l = (char*)0x00000058F24FF5C8; *l= 0x00000058F24FF584;}
再用RemoteDll注入
这里不会出错,但写法是不对的,l2需要是**的二级地址。
#include<stdio.h>#include<Windows.h>void main() { char l = 'A'; char* l1 = &l; char* l2 = &l1; //这里编译没有出错,但有警告提示,这个是个错误,一定要记录指针长度是8(x64) printf("%d,%d\n", sizeof(l1), sizeof(l2)); printf("%p,%p\n", l1, l2);}指针的算术运算
指针是一个用数值表示的地址。因此,您可以对指针执行算术运算。可以对指针进行四种算术运算:++、--、+、-。
作为一种特殊的变量,指针可以进行一些运算,但并非所有的运算都是合法的,指针的运算主要局限在加减算术和其他一些为数不多的特殊运算
void main() { int x = 5; int* p = x;//这里是不对的,5会被当成地址}
void main() { int x = 5; int* p1 = &x; int* p2 = p1; //p1,p2都会指向x的地址 printf("%p,%p", p1, p2);}
这里查看一下指针地址变化,*p++在循环指针时int就是4位一变,double是8位一循环
void main() { int a[5] = { 1,2,3,4,5 }; printf("%p\n", a); for (int i = 0; i < 5; i++) { printf("%d,%d\n", a[i], *(a + i)); } printf("int:%d\n", sizeof(int)); printf("double:%d\n", sizeof(double)); //int长度是4 for (int *p = a; p < a+5; *p++) { printf("%p\n", p); *p = *p + 1; printf("%d\n", *p); }}
void main() { int a[5] = { 1,2,3,4,5 }; //int长度是4 int* p = a; for (int i = 0; i < 5; i++) { printf("%d,%p\n", *p, p); p++; }}
地址传递
void main() { int x = 10; int* p = &x; printf("%d\n", x); int* p1 = p;//地址变化 *p1 = 12; printf("%d\n", x);}指针相减
指针和指针可以做减法操作,但不适合做加法运算;
指针与指针的相减操作,表示两个指针指向的内存位置之间相隔多少个元素(注意是元素,并不是字节数)。
#include<stdio.h>void main() { int ary[5] = { 1,2,3,4,5 }; int* p1 = &ary; int* p2 = &ary[4]; int count = p2 - p1; printf("%d", count);}
即是两个之间之间的元素数目为 4 个。
不同类型的指针不允许相减
#include<stdio.h>void main() { int ary[5] = { 1,2,3,4,5 }; int* x1 = &ary[3] - 1; printf("%d,%p", *x1,x1);}
标签: #c语言中使用变量必须先什么后什么 #c 指针加1