arr的范围时,p就是野指针 *(p++) = i; } return 0; } 可以看到,调试运行之后程序直接就抛出异常了,所以为了安全最好要避免野指针的出现。...【示例】:写⼀个函数,交换两个整型变量的值 错误示范 #include void Swap1(int x, int y) { int tmp = 0; tmp = x; x =...解决办法:我们现在要解决的就是当调用Swap函数的时候,Swap函数内部操作的就是main函数中的a和b,直接 将a和b的值交换了。...那么就可以使用指针了,在main函数中将a和b的地址传递给Swap函数,Swap函数里边通过地址间接的操作main函数中的a和b,并达到交换的效果就好了。...,这⾥调用Swap2函数的时候是将变量的地址传 递给了函数,这种函数调用方式叫:传址调用。
本文将通过代码示例和图示,详细分析这两种参数传递方式的工作原理,并探讨它们的优缺点和应用场景。 C语言 传值调用 1. 什么是传值调用? 传值调用是C语言中最常见的函数参数传递方式。...在传值调用的情况下,我们尝试交换两个变量 a 和 b: #include void Swap(int x, int y) { int tmp = x; x = y;...与传值调用不同,传址调用会将变量的地址传递给函数,这样函数就能够直接修改原始变量的值。在传址调用中,传递的是变量的指针,函数通过指针访问并修改原始变量的内容。 2....传址调用:当需要修改传入的参数,或者当参数较大(如数组、结构体等)时,传址调用更为高效。 小结 通过上述分析,我们深入探讨了C语言中两种常见的参数传递方式:传值调用和传址调用。...我们通过代码示例展示了它们在实际使用中的不同表现,并详细解释了它们的优缺点和应用场景。 传值调用将参数的副本传递给函数,适用于不需要修改外部变量的情况。
在实际运行中,尽管这些代码可能不会立即导致错误,但它们会导致未定义的行为。由于释放的内存空间可能被其他变量或函数使用,因此在这种情况下,pa可能会包含无法预测的值,或者程序可能会崩溃。...因此,虽然这些代码可能不会立即报错,但它们是不安全的,并且可能导致程序出现问题。...在调⽤Swap1函数时,将a和b传递给了Swap1函数,在Swap1函数内部创建了形参x和 y 接收a和b的值,但是x的地址是0x008ffdc4,y的地址是0x008ffdc8,x和y确实接收到了a和...Swap1函数在使⽤的时候,是把变量本⾝直接传递给了函数,这种调⽤函数的⽅式我们之前在函数的时候就知道了,这种叫传值调⽤。...b=%d\n", a, b); return 0; } 我们可以看到实现成Swap2的⽅式,这⾥调⽤Swap2函数的时候是将变量的地址传递给了函数,这种函数调⽤⽅式叫:传址调⽤ 结论: 传址调用
3.2指针的使用和传地址调用 问题引入 有两个变量a=10,b=20.我们想让这两个值进行交换,按照之前的逻辑可能会写出这样的错误代码。 可以发现,这两个值并没有发生交换,这是为什么呢?...在调用Swap函数时,将a和b的值传给了x和y,并且为x和y单独开辟了一块空间,x的地址为0x00f3fd88,y的地址为0x00f3fd8c。...因此需要使用指针来帮助我们进行两个值的交换。 (涉及到函数栈帧的创建和销毁) 结论:实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实参。...传址调用 使用指针了,在main函数中将a和b的地址传递给Swap函数,Swap 函数里边通过地址间接的操作main函数中的a和b,并达到交换的效果就好了。...调用Swap函数的时候是将变量的地址传递给了函数,这种函数调用方式叫:传址调用。 总结 传址调用,可以让函数和主调函数之间建⽴真正的联系,在函数内部可以修改主调函数中的变量。
实例中我们定义了回调函数 getNextRandomValue(),它返回一个随机值,它作为一个函数指针传递给 populate_array() 函数。...populate_array() 将调用 10 次回调函数,并将回调函数的返回值赋值给数组。...所以我们需要传一个数组,数组中元素的个数,每个元素的大小,和一个函数; 因为 qsort 函数在设计的时候,作者并不知道你要比较什么,且也不知道你想要怎么比较,所以这个函数就需要我们自己来完成,我们写这个函数时...它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来。...我们知道冒泡排序是两个相邻元素之间的比较,所以说在设计函数参数时,参数应该指向的是数组中两个相邻的元素,可是我们在设计函数时并不知道参数的具体类型,又该怎么向函数传数组中的两个相邻元素呢?
来思考这样的问题: 设计一个函数,交换两个变量的值。...那么就可以使用指针了,在main函数中将a和b的地址传递给Swap函数,Swap函数里边通过地址间接的操作main函数中的a和b,并达到交换的效果就好了。...,顺利完成了任务,这里调用Swap函数的时候是将变量的地址传递给了函数,这种函数调用方式叫:传址调用。...&a,而 p2 中存放的是 a,将它们用 %p 占位符打印出来: 很显然,这两个指针指向的地址是完全相同的!...一维数组传参的本质 数组我们之前也讲过了,数组是可以传递给函数的,这个小节我们讨论一下数组传参的本质。
+整数 } 当打印*(p+i)的值时,i作为整数是在不断增加的,那么在此基础上指针的值也会随之增加,在数组上的体现就是向前进i。...(2)野指针的成因 a.指针未初始化 当一个指针变量被声明但没有被初始化时,它可能会包含一个随机的内存地址,这可能会导致野指针的出现。...(3)传址调用 设想:通过函数来交换值 得到的结果是: 原因就是,形参和实参都有自己独立的空间,对于在函数内部形参的交换并不会影响到主函数内实参的变量的改变。对形参的影响是不会影响实参的。...如果我们需要解决这个问题,就需要用到传址调用。 结果就是: 在传址调用中,函数参数的地址被传递给函数的形参。这意味着在函数内部对形参的修改会影响到实参的值。...传递给函数的是实参的地址,函数内部对形参的修改会影响到实参。
例如:写⼀个函数,交换两个整型变量的值 ⼀番思考后,我们可能写出这样的代码: 我们发现其实没产⽣交换的效果,这是为什么呢? 调试⼀下,试试呢? ...我们发现在main函数内部,创建了a和b,a的地址是0x00cffdd0,b的地址是0x00cffdc4,在调用 Swap1函数时,将a和b传递给了Swap1函数,在Swap1函数内部创建了形参x和y接收...我们现在要解决的就是当调用Swap函数的时候,Swap函数内部操作的就是main函数中的a和b,直接 将a和b的值交换了。...那么就可以使用指针了,在main函数中将a和b的地址传递给Swap函数,Swap 函数⾥边通过地址间接的操作main函数中的a和b,并达到交换的效果就好了。...我们可以看到实现成Swap2的方式,顺利完成了任务,这⾥调用Swap2函数的时候是将变量的地址传 递给了函数,这种函数调用方式叫:传址调用。
六、野指针 野指针,野指针没有明确指向空间的指针,不确定,随机性,没有预测的。 什么场景会出现野指针?...八、指针的应用传值调用和传地址调用 写一个函数实现对两整数的交换: 传值调用 void swap(int x, int y) { int temp = x; x = y; y = temp; }...,函数swap在接受实际参数时创建了两个形式参数,形式参数只是实际参数的一份临时拷贝,在函数了确实完成了两个整数的交换,但出函数后形式参数被销毁,实参没有发生任何改变,这是传值调用将,实际参数的值传递给形式参数...,在函数里都对指针变量x,y进行了解引用,对指针变量解引用可以通过地址来找到它所对应的值,这样对指针变量交换后,主函数里的变量a、变量b也发生了交换。...p取地址,而是将字符变量p的地址传递给test函数由于传递的是一个指针变量的地址所以使用二级指针来接受,对二级指针变量p解引用一次就找到了指针变量p的地址然后将一个字符串,第一个字符的地址放在里面,现在
回调函数是什么 回调函数就是一个通过函数指针调用的函数。 如果你把函数的指针(地址)作为参数传递给另个函数,当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数。...qosrt 排序的原理了,没错,就是根据 size 的大小去解引用 base 指向的数据,然后调用 compare 函数比较两个数据的大小,根据其返回结果按照字节依次将两个数据中的数据进行交换(也就是交换内存中这两个数据的每个字节存储的数据...,所以我们可以直接将这两个参数强制类型转换为 int* 类型的变量,然后按照要求设计返回值,在返回时,除了上面的做法,还有一种写法: int int_cmp(const void* p1, const...void*)); 还有我们前面分析出来的 qsort 的原理:根据 size 的大小去解引用 base 后的数据,然后调用 compare 函数比较两个数据的大小,根据其返回结果按照字节依次将两个数据中的数据进行交换...(也就是交换内存中这两个数据的每个字节存储的数据)。
详细介绍: strcpy函数用于将一个字符串复制到另一个字符串中。 具体而言,strcpy函数接收两个参数:目标字符串的指针和源字符串的指针。目标字符串应该具有足够的空间来容纳源字符串的内容。...)时,8和7是实际参数,被传递给函数进行计算。...4.2.2 传址调用的适用场景 1. 当您需要在函数内部修改外部变量的值时,比如要对一个数组进行排序,或者修改某个结构体中的成员变量。 2....当需要节省内存空间,避免复制大型数据结构(如大型数组或复杂结构体)时,通过传址调用可以直接操作原始数据,而不用复制一份。 3....} 在这个示例中,在 outer 内部尝试定义 inner 是不符合 C 语言语法规则的,会导致编译错误。
/*int main() { //一个局部变量不初始化的话,它的值是随机的 int* p;//p是局部变量,没有初始化,其值是随机值,如果将p中的值当做地址, //解引用操作就会形成非法访问...:a=3 b=5 //交换后:a = 3 b = 5 //很明显,出问题了 //当实参传递给形参的时候,形参是实参的一份临时拷贝, //对形参的修改不会影响实参 //那么如何修改呢?...", a, b); return 0; } //在这两个代码中,Swap1是传值调用 //Swap2是传址调用,直接将变量本身传递过去了 //当我们采用的是传值调用,形参和实参占用的是不同的空间...// 这意味着函数内部对参数值所做的任何修改都不会影响原始变量。 //原始数据不会被修改,传值调用通常被认为是安全的 //传址调用涉及将参数的内存地址传递给函数。...传值调用:实际上是将参数值复制到函数内部的一个局部变量中,这意味着函数内部对参数值所做的任何修改都不会影响原始变量,原始数据不会被修改 传址调用:涉及将参数的内存地址传递给函数,这意味着函数可以直接访问和修改原始变量
我们发现在main函数内部,创建了a和b,a的地址是0x00cffdd0,b的地址是0x00cffdc4,在调⽤Swap1函数时,将a和b传递给了Swap1函数,在Swap1函数内部创建了形参x和y接收...Swap1函数在使⽤的时候,是把变量本⾝直接传递给了函数,这种调⽤函数的⽅式我们之前在函数的时候就知道了,这种叫传值调⽤。...我们现在要解决的就是当调⽤Swap函数的时候,Swap函数内部操作的就是main函数中的a和b,直接将a和b的值交换了。...那么就可以使⽤指针了,在main函数中将a和b的地址传递给Swap函数,Swap函数⾥边通过地址间接的操作main函数中的a和b,并达到交换的效果就好了。...的⽅式,顺利完成了任务,这⾥调⽤Swap2函数的时候是将变量的地址传递给了函数,这种函数调用方式叫:传址调用。
野指针成因: 1.指针变量没有初始化 int *p;//局部变量指针未初始化,默认为随机值 *p = 20; 规避方法,将指针初始化 当不知道指针变量该指向哪里时...*p = test(); printf("%d\n", *p); return 0; } 七、传值调用与传址调用 通过一个题来感受一下什么是传值调用,什么是传址调用 写一个函数,交换整型变量的值...这是因为变量x和y是在Swap函数内部创建的,变量x和变量y是两个独立的空间,因此x和y交换值对变量a和b是没有影响的。 像这样把变量的值传给函数,这就是传值调用。...把实际参数传递给形式参数时,形参会单独创建一个空间来接收实参,因此形参的改变对实参没有影响。 所以我们可以将a和b的地址传过去,通过地址将a和b的值交换。...像这样把变量的地址传递给函数,这就是传址调用。 所以在函数中需要改变主调函数中变量的值,我们可以采用传址调用;如果仅需要在函数内利用变量的值来计算,就采用传值调用。
} return 0; } 最后圈起来的这两个值就是随机值,也就是野指针。...8.2 传址调⽤ 写⼀个函数,交换两个整型变量的 打印 交换前:a=2 b=3 交换前:a=2 b=3 我们发现传值只是将数值拷贝了一份,但a和x,b和y的地址是不一样的。...在函数中x和y进行了交换,返回的值还是Swap函数调⽤结束后回到main函数,a和b的没法交换。...Swap1函数在使⽤ 的时候,是把变量本⾝直接传递给了函数,这种调⽤函数的⽅式我们之前在函数的时候就知道了,这 种叫传值调⽤。 既然传值解决不了问题那只能用传地解决。...交换前:a = 2 b = 3 交换后:a = 3 b = 2 这⾥调⽤Swap函数的时候是将变量的地址传 递给了函数,这种函数调⽤⽅式叫:传址调⽤。
最重要的是:当实参传递给形参的时候,形参只是实参的一份临时拷贝,通过改变形参不能使实参发生改变!!! ---- 二、函数调用时的处理 1.传值 看到传值,那么就是调用函数时的实参是具体的值。...2.传址 看到传址,那么就是调用函数时的实参是变量的地址。...我们通过传递a和b的地址,分别给形参中的指针变量int *px=&a,int *py=&b,来通过解引用交换两个变量的值!...指针变量可以通过解引用*px,*py,来通过地址访问到a和b的值,交换*px,*py的值,即交换a,b的值。 ---- 那为什么不像第一种那样传值交换呢? ...所以,只有调用函数时,函数要改变实参的值的时候,才需要传址过去。
前言 在学习 C语言 时,“传值调用” 和 “传址调用” 是两个至关重要的概念,涉及到函数与变量的交互机制,以及如何有效管理内存资源。...本文将对这两个概念进行深入探讨,分析它们的原理、实现方式、各自的优缺点,并结合实际代码示例来帮助你全面掌握这两种方法。...传值调用(Call by Value) 传值调用是指在函数调用过程中,向函数传递的是实参的值的副本,即将实参的值复制一份传递给函数的形参。因此,函数内部对形参的操作是不会影响实参本身的。...传址调用: 适用于需要函数直接修改原始数据的场景,例如交换数据、修改数组内容或者动态调整数据结构。传址调用的最大优势在于其高效性,因为它避免了数据的重复拷贝。...为了避免此类错误,必须对指针进行严格管理,并且在设计函数接口时明确函数对参数的修改行为。
前面我们已经了解了指针的基本概念以及简单的使用,那么什么问题一定要使用指针解决呢? 我们来接着往下学习: 传值调用和传址调用 问题:写一个函数,交换两个变量的值。...我们可以看到在main函数内部,创建了a和b,a的地址是0x009af998,b的地址是0x009af98c,在调用Swap函数时,将a和b传递给了Swap函数,在Swap函数内部创建了形参x和y接收a...Swap函数在使⽤的时候,是把变量本⾝直接传递给了函数,这就是传值调⽤。 结论:实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实 参。...调⽤Swap函数的时候是将变量的地址传 递给了函数,这就是传址调⽤。...n", a, b); return 0; } 常见错误 在写这个函数内部的代码的时候可能会出现一些错误。
arr的范围时,p就是野指针,直接报错。...我们常用的动态内存开辟函数,如malloc,calloc,realloc,如果它们开辟动态内存失败就会返回空指针,所以动态开辟函数后,都要判断是否开辟成功。...传址调用,可以让函数和主调函数之间建立真正的联系,在函数内部可以修改主调函数中的变量。 2. 如果函数中只是需要主调函数中的变量值来实现计算,就可以采用传值调用; 3....如果函数内部要修改主调函数中的变量的值,就需要传址调用。 传值调用 1. 实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实参。...将main函数中将a和b的地址传递给Swap函数,Swap 函数里边通过地址,间接操作main函数中的a和b,达到交换的效果。
其实指针类型是有特殊意义的,我们接下来继续学习 对比下面两个代码,在调试时它们有什么不同: //代码1 #include int main() { int n = 0x11223344...它的运行结果如下: 我们发现函数exg并没有帮我们把这两个变量的值交换,这是因为我们传参时,会把变量的值传过去,但是只是把值传过去,在函数exg的栈帧中会重新创建a和b来接收传过来的值,...所以实现交换操作时,只是将exg中的a和b交换,然后函数结束时就销毁了,并没有起到实际作用 那要怎么办呢?...我们的需求就是将main函数中真正的a和b进行交换,我们可以使用传址调用,什么意思呢?...调⽤exg函数的时候是将变量的地址传递给了函数,这种函数调⽤⽅式叫:传址调⽤ 传址调⽤,可以让函数和主调函数之间建⽴真正的联系,在函数内部可以修改主调函数中的变量;所以未来函数中只是需要主调函数中的变量值来实现计算
领取专属 10元无门槛券
手把手带您无忧上云