C语言 指针基础篇 数组,函数与指针的运用 2 14
下面看看如何在函数中运用指针吧
下面是往函数传入指针的简单操作,不是传入数组的。判断一个a是否大于b是的话给,是的话对其进行操作,不是的话就直接返回。
#include <stdio.h>
int main(){
int num1,num2,*p1,*p2;
p1 = &num1,p2=&num2;
scanf("%d%d",&num1,&num2); int fun(int *n1,int *n2); //我们在声明函数时候,要定义好“指针变量”
if(*p1<*p2){
fun(p1,p2); //而在传入值的时候只需要把指针变量传入进去就行了,这里没有*是因为指针变量值需要在声明的时候加*
}
printf("max num is:%d\nmin mum is:%d",*p1,*p2); //这里的*P就是解引用的操作
return ;
}
int fun(int *n1,int *n2){ //声明的指针变量和定义的指针变量的名字必须相同
int tmp;
tmp = *n1;
*n1 = *n2;
*n2 = tmp;
return ;
}
下面是函数中在运用传入指针的时候的错误操作
错误1:
int fun(int *n1,int *n2){
int tmp;
tmp = n1;
n1 = n2;
n2 = tmp;
return ;
}
原因:不能达到预期结果,因为这只交换了p1和p2的值,只是交换了他们的储存空间,没有交换内容。并且本身修改后不能传回实参,即不能传到main函数,最直接的就是编译器会直接报错。
错误2:
int fun(int *n1,int *n2){
int tmp*;
tmp* = *n1;
*n1 = *n2;
*n2 = *tmp;
return ;
}
原因:上述方式,定义了一个未知空间temp,并且通过指针修改了其数据。如果temp中存的是非常重要的内容,那么程序就会出问题,所以这种方法也是非常不可取的。但是编译的时候是不会报错的。
错误3:
int fun(int n1,int n2){
int tmp;
tmp = n1;
n1 = n2;
n2 = tmp;
return ;
}
原因:能传递,但是不能输出交换后的值。
错误4:
int fun(int *n1,int *n2){
int tmp;
tmp = n1;
n1 = n2;
n2 = tmp;
return ;
}
原因:这样根本就没有调用到传入的值,所以也不会进行操作。
#include <stdio.h>
int main(){
int num1,num2,*p1,*p2;
p1 = &num1,p2=&num2;
scanf("%d%d",&num1,&num2); int fun(int *n1,int *n2);
if(*p1<*p2){
fun(p1,p2);
}
printf("max num is:%d\nmin mum is:%d",*p1,*p2); //这里取的是经过函数操作后的p1和p2,并没有用返回值。
return ;
}
int fun(int *n1,int *n2){
int tmp;
tmp = n1;
n1 = n2;
n2 = tmp;
return ;
}
而在上面你也可以看到,我们并没有取返回值。但是我们可以获取到经过函数操作后的结果。
我们再弄一个例子,输入三个数。按照大小排列。用指针的方式实现:
#include <stdio.h>
int main(){
int a,b,c,*p1,*p2,*p3;
printf("Please input two num:");
p1 = &a,p2=&b,p3=&c;
scanf("%d %d %d",&a,&b,&c);
int pd(int *num1,int *num2,int *num3);
pd(p1,p2,p3);
printf("%d>%d>%d",*p1,*p2,*p3);
return ;
}
int pd(int *num1,int *num2,int *num3){
int lj(int *n1,int *n2);
int i;
for (int i = ; i < ; ++i) {
if (*num1 < *num2) {
lj(num1, num2);
} else if (*num1 < *num3) {
lj(num1, num3);
} else if (*num2 < *num3) {
lj(num2, num3);
}
}
return ;
}
int lj(int *n1,int *n2){
int tmp;
tmp = *n1;
*n1 = *n2;
*n2 = tmp;
return ;
}
//这个代码有两个要点:
//1,他们的都是靠指针进行返回的,也就是说可以返回多个值
//2,在进行逻辑的判断或其他的操作的时候就把指针转换成值,如果是函数进行传值的话就用指针进行传递。
把指针作为函数的返回值
方法:1,定义函数的时候类型定义成指针类型。2,返回值是一个地址。
如下例子:
#include <stdio.h>
int main(){
char str[] = "luotianyi"; char* found(char* str,char ch);
char* p = found(str,'i');
if (p == NULL){
printf("没有此字符\n");
}
else{
printf("输出此字符:%s\n",p); //输出字符串,因为数组的名字是数组的首地址,又因为是地址。所以不需要加上“&”所以也不需要加上“*”。只有字符串才可以,字符不行。
}
return ;
}
//我们先定义函数的类型是指针类型
char* found(char* str,char ch){ //这里的括号里面的char后面要加上“*”是因为我们在声明和定义的时候没有说str是一个数组,因此只能通过
//“*”把传入的首地址转换为其元素的值,我们才能在下面对其进行操作。如果把声明和定义换成:char str []也是可以的
int i=;
while (str[i]){
if (str[i] == ch){
return &str[i]; //把需要的值进行返回的值的地址进行返回。
}
i++;
}
return NULL;
}
上面的里面的判断使用数组进行的,而我们可以用指针进行判断。
如下例子:
#include <stdio.h>
int main(){
char str[] = "luotianyi";
char* found(char* str,char ch);
char* p = found(str,'i');
if (p == NULL){
printf("没有此字符\n");
}
else{
printf("输出此字符:%s\n",p); //输出字符串,以为数组名是数组的首地址。因此不需要加上“&”所以在获取的时候也不需要加上“*”。只有字符串才可以,字符不行。
}
return ;
}
//我们把声明的类型换成是指针类型
char* found(char* str,char ch){ //这里的括号里面的char后面要加上“*”是因为我们在声明和定义的时候没有说str是一个数组,因此只能通过
//“*”把传入的首地址转换为其元素的值,我们才能在下面对其进行操作。如果把声明和定义换成:char str []也是可以的
while (*str){ //这里的“*”就是获取指针的值,其实与str[i]是一样的
if (*str == ch){
return str; //这里的str在传入的时候就已经规定是指针的类型了,因此不需要再次*
}
str++; //对指针的自加操作
}
return NULL;
}
下面是数组如何运用指针的
数组的地址其实是这样的,例如:int a[2] = {0,1,2};这样的话其实在内存中是对其每一个元素都开辟了一个地址的,假设第一个元素的地址是101,第二个是105,第三个就是这是因为:1,int本身就占4个字节,每一个int的元素也是占4个字节。2,数组的地址是具有连贯性的,是一个接着一个的。3,我么可以通过指针的偏移来取出一个个数组的内容。而这个的数组的地址,其实就是第一个元素的地址。下面就让我们来一个个的证明这些观点
数组的地址就是数组第一个元素的地址
#include <stdio.h>
int main()
{
int sz[] = {,,,};
printf("%p\n",&sz); //取整个数组的地址
printf("%p\n",&sz[]); //取第一个元素地址
return ;
}
//输出结果:
//0xffffcc10
//0xffffcc10
例子
每一个元素占4个字节,数组的地址具有连贯性
#include <stdio.h>
int main()
{
int sz[] = {,,,};
printf("%ld\n",&sz[]);
printf("%ld\n",&sz[]);
printf("%ld\n",&sz[]);
printf("%ld\n",&sz[]); return ;
}
//这里本来应该是用%p输出地址的,%p输出的是16进制的。但是为了方便看改正了%lp
/*
* 输出结果
*4294954000
*4294954004
*4294954008
*4294954012
*/
例子
看看如何通过指针的偏移,进行调用
#include <stdio.h>
int main()
{
int sz[] = {,,,};
int *p = &sz[];
printf("%d\n",*(p+));
printf("%d\n",*(p+));
return ;
}
例子
下面我们来看一个如何用指针运用数组
#include <stdio.h>
int main()
{
int sz[] = {,,,};
int *p; //把数组的首字符给了指针p
int num =;
for (p = &sz[];p<=&sz[];p++){ //在这里我们的循环是用地址来定义的,这里直接定义成&sz也可以,但是有警告
num = num + *p; //而我们也可以用地址来获取到对应的值
}
printf("num : %d",num);
return ;
}
例子
下面总结下,有三种方法访问数组;
1,下标法
#include <stdio.h>
int main() {
int num[] = {,,,,,,,,,};
for(int i=;i<;i++){
printf("%d\n",num[i]);
}
return ;
}
例子
2,通过数组名字获取到期地址,找出地址的值。
#include <stdio.h>
int main() {
int num[] = {,,,,,,,,,};
printf("%ld\n",num); //这里可以看出,我们直接访问这个数组的话是直接访问到地址的:4294953968为了
// 方便我们用长整型的方法输出
for (int i = ; i < ; ++i) {
printf("%d\n",*(num+i)); //因为上面直接访问了 数组名字得到的是地址,所以我们直接在数组前面加上*就可以
// 直接找到地址所对应的值
//这里加i实际上因为类型的原因是每次加上四个字节
}
return ;
}
例子
3,用指针变量通过指针的偏移而找到值。
#include <stdio.h>
int main() {
int num[] = {,,,,,,,,,};
int *p = &num[];
for(int i= ;i<;i++,p++){
printf("%d\n",*p);
}
return ;
}
例子
数组的指针偏移1表示指针往右边移动了一个类型,例如:int的类型加1等于指针地址加上了4个字节。
指针通过循环输出了数组所有的元素,然后指针本身就变成了一个野指针。我们可以通过过:野指针-数组名 =数组的个数(也可以说是指针的偏移量)
函数传入数组
数组做函数参数,说具体是指向数组的指针变量做函数参数。
由于数组名是该数组的首地址,指针变量的值也是首地址,所以函数的实参和形参都可以指向数组名或者数组的指针。于是有了以下四种对应关系:
例子:
#include <stdio.h>
int main()
{
float ave(int *b, float num); //这里的是声明函数
int counter,a[] = {};
float all =, res; scanf("%f", &all);
for(counter = ; counter < all; counter++)
{
scanf("%d", &a[counter]);
}
res = ave(a, all); //这里把数组的名字传入了函数定义的指针变量。和输入第一次输入的次数
printf("%f", res);
return ;
} float ave(int *b, float num) //这里和上面声明函数一样
{
int i, sum =;
float ave;
for(i = ; i < num; i++)
{
sum = sum + b[i];
}
ave = (float)sum/num;
return ave;
}
这里传入函数ave的是数组a的首地址,而不是将整个数组传入。传入首地址后,ave函数就按照一定顺序去访问a的储存空间,从而得到a中的数据。
当然float ave(int *b, float num) 也可以写为float ave(int b[], float num) 或者float ave(int b[100], float num) 也就是说b[] 后面方括号内可以是任意数字,因为那个数字是没有意义的,真真起作用的是b和方括号。
总结一下这部分就是:
数组做形参,其实就是指针做形参。只要指针向函数内传入数组首地址,那么函数形参和实参是指同一数组。函数内部对数组所做的处理,就是对主调函数中的实参数组所作的处理,可以传回主调函数。
指针和字符串与函数
f(int arr[ ] ,int n)但是在编译时是将arr按指针变量处理的,相当于将函数 f 的首部写成 f ( int* arr,int n)。这两种写法是等价的,而%s的输出可以是字符串的地址,而不需要解引用。
输出字符串有三种方法,如下所示。
#include <stdio.h>
int main(){
char ch1[] ="luotianyi"; //第一种是用数组的方式输出字符串
printf("%s\n",ch1);
char *ch2 = "luotianyi"; //第二种是利用指针变量保存字符串
printf("%s\n",ch2);
printf("luotianyi"); //第三种是直接用把字符串放到printf中
return ;
}
这三种方法有2个区别,第一种利用数组的方式存储是把字符串存储在栈中(也就是可以进行修改的地方,也可以进行输出)。第二种和第三种是保存在堆中的(也就是只能输出,但是不允许进行修改)。
#include <stdio.h>
int main(){
char ch1[] ="luotianyi";
ch1[] = 'w'; //可以进行修改
printf("%s\n",ch1);
char *ch2 = "luotianyi";
*ch2+ = 's'; //error: lvalue required as left operand of assignment
printf("%s\n",ch2);
printf("luotianyi");
return ;
}
下面我们看看字符串是如何传入函数中的,我们分别演示下用指针变量和数组变量进行。
#include <stdio.h>
int main(){
char str1[] = "luotianyi";
char* str2 = "my wife";
int strpri(char ch1[],char* ch2) ;
strpri(str1,str2);
return ;
}
int strpri(char ch1[],char* ch2){ //我们分别用两种方法传入
char* tmp; //创建一个指针对其进行转换
tmp = ch1;
ch1 = ch2;
ch2 = tmp;
ch2[] = 'z';
printf("%s\n",ch1); //在这里可以看出指针变量所指向的字符串内部虽然不可以改变,但是可以对其整体进行其他的操作。
//也就是说字符串单个字符的操作是不可以的,但是可以对其整体进行操作
printf("%s\n",ch2); //这里可以看出我们可以对数组变量的字符串进行操作
return ;
}
例子
堆与栈的区别还有就是栈可以保存多份一样的值,而堆只保存一份,其余的也要调用的话就是多个变量都是指向堆的这一份。
#include <stdio.h>
int main(){
char* a = "luotianyi";
char* b = "luotianyi";
printf("%ld\n",a);
printf("%ld\n",b);
return ;
}
/*
* 4299173896
* 4299173896
* */
堆的示例
指针字符串 or 数组字符串
#include <stdio.h>
int main(){
char* ch[] = {"luotianyi","wsj","woaini"}; //这就是创建一个数组字符串或是叫做指针字符串
for (int i = ; i < ; ++i) {
printf("%s\n",ch[i]); //输出全部
}
printf("%c\n",ch[][]); //第一个下标是第几排,第二个是低级列
printf("%c\n",*(*(ch+)+)); //外面的数字是第几横排,里面的是横排的第几个数字
return ;
}
---------------------
部分来源和代码出自以下链接
来源:CSDN
原文:https://blog.csdn.net/C2681595858/article/details/53750577
版权声明:本文为博主原创文章,转载请附上博文链接!
C语言 指针基础篇 数组,函数与指针的运用 2 14的更多相关文章
- 2.4JAVA基础复习——JAVA语言的基础组成数组
JAVA语言的基础组成有: 1.关键字:被赋予特殊含义的单词. 2.标识符:用来标识的符号. 3.注释:用来注释说明程序的文字. 4.常量和变量:内存存储区域的表示. 5.运算符:程序中用来运算的符号 ...
- 【C语言】-指向一维数组元素的指针
本文目录 一.用指针指向一维数组的元素 二.用指针遍历数组元素 三.指针与数组的总结 四.数组.指针与函数参数 说明:这个C语言专题,是学习iOS开发的前奏.也为了让有面向对象语言开发经验的程序员,能 ...
- 【C语言】指向一维数组元素的指针
本文目录 一.用指针指向一维数组的元素 二.用指针遍历数组元素 三.指针与数组的总结 四.数组.指针与函数参数 前面我们已经学习了指针,如果指针存储了某个变量的地址,我们就可以说指针指向这个变量.数组 ...
- 大数据系列博客之 --- 深入简出 Shell 脚本语言(基础篇)
首先声明,此系列shell系列博客分为四篇发布,分别是: 基础篇:https://www.cnblogs.com/lsy131479/p/9914747.html 提升篇:https://www.cn ...
- C语言复习---二维数组和二级指针的关系:没关系,别瞎想(重点)
前提:一维数组和一维指针为什么可以替换使用? ] = { , , }; int *p = a; ; i < ; i++) printf("%d ", *(p + i)); 上 ...
- python 基础篇 11 函数进阶----装饰器
11. 前⽅⾼能-装饰器初识本节主要内容:1. 函数名的运⽤, 第⼀类对象2. 闭包3. 装饰器初识 一:函数名的运用: 函数名是一个变量,但他是一个特殊变量,加上括号可以执行函数. ⼆. 闭包什么是 ...
- C++二维数组、指针、对象数组、对象指针
项目中用到,随手记一下: 1.二维数组.与指针 创建二维数组指针的方式: a.已知一维的大小 1 int **array=new int *[rows]; 2 (for int i=0;i<ro ...
- Java语言程序设计(基础篇) 第七章 一维数组
第七章 一维数组 7.2 数组的基础知识 1.一旦数组被创建,它的大小是固定的.使用一个数组引用变量,通过下标来访问数组中的元素. 2.数组是用来存储数据的集合,但是,通常我们会发现把数组看作一个存储 ...
- Java语言程序设计(基础篇) 第八章 多维数组
第八章 多维数组 8.2 二维数组的基础知识 二维数组中的元素通过行和列的下标来访问. 8.2.1 声明二维数组变量并创建二维数组 下面是二维数组的语法: 数据类型[][] 数组名; int[][] ...
随机推荐
- py2neo的使用(转)
转自:https://blog.csdn.net/sinat_26917383/article/details/79901207#24-%E7%B1%BB%E4%BC%BCset%E7%9A%84%E ...
- 利用linux curl爬取网站数据
看到一个看球网站的以下截图红色框数据,想爬取下来,通常爬取网站数据一般都会从java或者python爬取,但本人这两个都不会,只会shell脚本,于是硬着头皮试一下用shell爬取,方法很笨重,但旨在 ...
- Mybatis useGeneratedKeys 填充自增主键值(使用Mysql)的原理分析
一.Mybatis配置 <insert id="insert" parameterType="com.test.TestDO" keyProperty=& ...
- 《Go程序设计语言》读书笔记-函数
函数包含连续执行的语句,可以使用代码中通过调用函数来执行他们,函数能够将一个复杂的工作切分成多个更小的模块,使多人写作变得容易.另外,函数对他的使用者隐藏了实现细节.这几方面的特性使得函数成为多数编程 ...
- Linux Apache虚拟主机配置方法
apache 虚拟主机配置 注意: 虚拟主机可以开很多个 虚拟主机配置之后,原来的默认/etc/httpd/httpd.conf中的默认网站就不会生效了 练习: 主机server0 ip:172.25 ...
- 转:Jmeter分布式测试
在使用Jmeter进行性能测试时,如果并发数比较大(比如最近项目需要支持1000并发),单台电脑的配置(CPU和内存)可能无法支持,这时可以使用Jmeter提供的分布式测试的功能. 一.Jmeter分 ...
- easyui 传递参数报错(错误:uncaught SyntaxError: Unexpected identifier)
转自:https://www.cnblogs.com/javaboy2018/p/8733585.html 代码: 按钮事件: function formatOper(val, row, index) ...
- Codeforces Round #552 (Div. 3) D题
题目网站:http://codeforces.com/contest/1154/problem/D 题目大意:给出n个数(0或1),还有a , b, a是蓄电池容量,b是电池容量,数为1时蓄电池可以充 ...
- xx星空面试题
一面 1.什么是多态 实现原理? 2.什么是重载?class加载原理? 3.常用设计模式,简单介绍 4.看过哪些java的书?android的书? 5.动态注册静态注册 优缺点?静态注册函数如何被调用 ...
- ArrayList的ConcurrentModificationException异常和多线程下的异常
一.ConcurrentModificationException ArrayList源码看为什么出现异常: public class ArrayList<e> extends Abstr ...