• C语言 指针基础篇 数组,函数与指针的运用 2 14


    下面看看如何在函数中运用指针吧

     下面是往函数传入指针的简单操作,不是传入数组的。判断一个a是否大于b是的话给,是的话对其进行操作,不是的话就直接返回。

     1 #include <stdio.h>
     2 int main(){
     3     int num1,num2,*p1,*p2;
     4     p1 = &num1,p2=&num2;
     5     scanf("%d%d",&num1,&num2);
     6 
     7     int fun(int *n1,int *n2);   //我们在声明函数时候,要定义好“指针变量”
     8     if(*p1<*p2){
     9         fun(p1,p2);             //而在传入值的时候只需要把指针变量传入进去就行了,这里没有*是因为指针变量值需要在声明的时候加*
    10     }
    11     printf("max num is:%d
    min mum is:%d",*p1,*p2); //这里的*P就是解引用的操作
    12     return 0;
    13 }
    14 int fun(int *n1,int *n2){       //声明的指针变量和定义的指针变量的名字必须相同
    15     int tmp;
    16     tmp = *n1;
    17     *n1 = *n2;
    18     *n2 = tmp;
    19     return 0;
    20 }

    下面是函数中在运用传入指针的时候的错误操作

    错误1:

    1 int fun(int *n1,int *n2){      
    2     int tmp;
    3     tmp = n1;
    4     n1 = n2;
    5     n2 = tmp;
    6     return 0;
    7 }

    原因:不能达到预期结果,因为这只交换了p1和p2的值,只是交换了他们的储存空间,没有交换内容。并且本身修改后不能传回实参,即不能传到main函数,最直接的就是编译器会直接报错。

    错误2:

    1 int fun(int *n1,int *n2){
    2     int tmp*;
    3     tmp* = *n1;
    4     *n1 = *n2;
    5     *n2 = *tmp;
    6     return 0;
    7 }

    原因:上述方式,定义了一个未知空间temp,并且通过指针修改了其数据。如果temp中存的是非常重要的内容,那么程序就会出问题,所以这种方法也是非常不可取的。但是编译的时候是不会报错的。

    错误3:

    1 int fun(int n1,int n2){
    2     int tmp;
    3     tmp = n1;
    4     n1 = n2;
    5     n2 = tmp;
    6     return 0;
    7 }

    原因:能传递,但是不能输出交换后的值。

    错误4:

    1 int fun(int *n1,int *n2){
    2     int tmp;
    3     tmp = n1;
    4     n1 = n2;
    5     n2 = tmp;
    6     return 0;
    7 }

    原因:这样根本就没有调用到传入的值,所以也不会进行操作。

     1 #include <stdio.h>
     2 int main(){
     3     int num1,num2,*p1,*p2;
     4     p1 = &num1,p2=&num2;
     5     scanf("%d%d",&num1,&num2);
     6 
     7     int fun(int *n1,int *n2);
     8     if(*p1<*p2){
     9         fun(p1,p2);
    10     }
    11     printf("max num is:%d
    min mum is:%d",*p1,*p2); //这里取的是经过函数操作后的p1和p2,并没有用返回值。
    12     return 0;
    13 }
    14 int fun(int *n1,int *n2){
    15     int tmp;
    16     tmp = n1;
    17     n1 = n2;
    18     n2 = tmp;
    19     return 0;
    20 }

    而在上面你也可以看到,我们并没有取返回值。但是我们可以获取到经过函数操作后的结果。 

    我们再弄一个例子,输入三个数。按照大小排列。用指针的方式实现:

     1 #include <stdio.h>
     2 int main(){
     3     int a,b,c,*p1,*p2,*p3;
     4     printf("Please input two num:");
     5     p1 = &a,p2=&b,p3=&c;
     6     scanf("%d %d %d",&a,&b,&c);
     7     int pd(int *num1,int *num2,int *num3);
     8     pd(p1,p2,p3);
     9     printf("%d>%d>%d",*p1,*p2,*p3);
    10     return 0;
    11 }
    12 int pd(int *num1,int *num2,int *num3){
    13     int lj(int *n1,int *n2);
    14     int i;
    15     for (int i = 0; i <3 ; ++i) {
    16         if (*num1 < *num2) {
    17             lj(num1, num2);
    18         } else if (*num1 < *num3) {
    19             lj(num1, num3);
    20         } else if (*num2 < *num3) {
    21             lj(num2, num3);
    22         }
    23     }
    24     return 0;
    25 }
    26 int lj(int *n1,int *n2){
    27     int tmp;
    28     tmp = *n1;
    29     *n1 = *n2;
    30     *n2 = tmp;
    31     return 0;
    32 }
    33 //这个代码有两个要点:
    34 //1,他们的都是靠指针进行返回的,也就是说可以返回多个值
    35 //2,在进行逻辑的判断或其他的操作的时候就把指针转换成值,如果是函数进行传值的话就用指针进行传递。

    把指针作为函数的返回值

    方法:1,定义函数的时候类型定义成指针类型。2,返回值是一个地址。

    如下例子:

     1 #include <stdio.h>
     2 int main(){
     3     char str[] = "luotianyi";
     4 
     5     char* found(char* str,char ch);
     6     char* p = found(str,'i');
     7     if (p == NULL){
     8         printf("没有此字符
    ");
     9     }
    10     else{
    11         printf("输出此字符:%s
    ",p);  //输出字符串,因为数组的名字是数组的首地址,又因为是地址。所以不需要加上“&”所以也不需要加上“*”。只有字符串才可以,字符不行。
    12     }
    13     return 0;
    14 }
    15 //我们先定义函数的类型是指针类型
    16 char* found(char* str,char ch){     //这里的括号里面的char后面要加上“*”是因为我们在声明和定义的时候没有说str是一个数组,因此只能通过
    17                                     //“*”把传入的首地址转换为其元素的值,我们才能在下面对其进行操作。如果把声明和定义换成:char str []也是可以的
    18     int i=0;
    19     while (str[i]){
    20         if (str[i] == ch){
    21             return &str[i];     //把需要的值进行返回的值的地址进行返回。
    22         }
    23         i++;
    24     }
    25     return NULL;
    26 }

    上面的里面的判断使用数组进行的,而我们可以用指针进行判断。

    如下例子:

     1 #include <stdio.h>
     2 int main(){
     3     char str[] = "luotianyi";
     4     char* found(char* str,char ch);
     5     char* p = found(str,'i');
     6     if (p == NULL){
     7         printf("没有此字符
    ");
     8     }
     9     else{
    10         printf("输出此字符:%s
    ",p);  //输出字符串,以为数组名是数组的首地址。因此不需要加上“&”所以在获取的时候也不需要加上“*”。只有字符串才可以,字符不行。
    11     }
    12     return 0;
    13 }
    14 //我们把声明的类型换成是指针类型
    15 char* found(char* str,char ch){     //这里的括号里面的char后面要加上“*”是因为我们在声明和定义的时候没有说str是一个数组,因此只能通过
    16                                     //“*”把传入的首地址转换为其元素的值,我们才能在下面对其进行操作。如果把声明和定义换成:char str []也是可以的
    17     while (*str){       //这里的“*”就是获取指针的值,其实与str[i]是一样的
    18         if (*str == ch){
    19             return str;    //这里的str在传入的时候就已经规定是指针的类型了,因此不需要再次*
    20         }
    21         str++;  //对指针的自加操作
    22     }
    23     return NULL;
    24 }

    下面是数组如何运用指针的

    数组的地址其实是这样的,例如:int a[2] = {0,1,2};这样的话其实在内存中是对其每一个元素都开辟了一个地址的,假设第一个元素的地址是101,第二个是105,第三个就是这是因为:1,int本身就占4个字节,每一个int的元素也是占4个字节。2,数组的地址是具有连贯性的,是一个接着一个的。3,我么可以通过指针的偏移来取出一个个数组的内容。而这个的数组的地址,其实就是第一个元素的地址。下面就让我们来一个个的证明这些观点

    数组的地址就是数组第一个元素的地址

     1 #include <stdio.h>
     2 int main()
     3 {
     4     int sz[] = {1,2,3,4};
     5     printf("%p
    ",&sz); //取整个数组的地址
     6     printf("%p
    ",&sz[0]);  //取第一个元素地址
     7     return 0;
     8 }
     9 //输出结果:
    10 //0xffffcc10
    11 //0xffffcc10
    例子

    每一个元素占4个字节,数组的地址具有连贯性

     1 #include <stdio.h>
     2 int main()
     3 {
     4     int sz[] = {1,2,3,4};
     5     printf("%ld
    ",&sz[0]);
     6     printf("%ld
    ",&sz[1]);
     7     printf("%ld
    ",&sz[2]);
     8     printf("%ld
    ",&sz[3]);
     9 
    10     return 0;
    11 }
    12 //这里本来应该是用%p输出地址的,%p输出的是16进制的。但是为了方便看改正了%lp
    13 /*
    14  * 输出结果
    15  *4294954000
    16  *4294954004
    17  *4294954008
    18  *4294954012
    19  */
    例子

    看看如何通过指针的偏移,进行调用

    1 #include <stdio.h>
    2 int main()
    3 {
    4     int sz[] = {1,2,3,4};
    5     int *p = &sz[0];
    6     printf("%d
    ",*(p+1));
    7     printf("%d
    ",*(p+2));
    8     return 0;
    9 }
    例子

    下面我们来看一个如何用指针运用数组 

     1 #include <stdio.h>
     2 int main()
     3 {
     4     int sz[] = {1,2,3,4};
     5     int *p;   //把数组的首字符给了指针p
     6     int num =0;
     7     for (p = &sz[0];p<=&sz[3];p++){  //在这里我们的循环是用地址来定义的,这里直接定义成&sz也可以,但是有警告
     8         num = num + *p;      //而我们也可以用地址来获取到对应的值
     9     }
    10     printf("num : %d",num);
    11     return 0;
    12 }
    例子

    下面总结下,有三种方法访问数组;

    1,下标法

    1 #include <stdio.h>
    2 int main() {
    3     int num[] = {0,1,2,3,4,5,6,7,8,9};
    4     for(int i=1;i<10;i++){
    5         printf("%d
    ",num[i]);
    6     }
    7     return 0;
    8 }
    例子

    2,通过数组名字获取到期地址,找出地址的值。

     1 #include <stdio.h>
     2 int main() {
     3     int num[] = {0,1,2,3,4,5,6,7,8,9};
     4     printf("%ld
    ",num);    //这里可以看出,我们直接访问这个数组的话是直接访问到地址的:4294953968为了
     5                                 // 方便我们用长整型的方法输出
     6     for (int i = 0; i < 10; ++i) {
     7         printf("%d
    ",*(num+i));    //因为上面直接访问了 数组名字得到的是地址,所以我们直接在数组前面加上*就可以
     8                                     // 直接找到地址所对应的值
     9                                     //这里加i实际上因为类型的原因是每次加上四个字节
    10     }
    11     return 0;
    12 }
    例子

    3,用指针变量通过指针的偏移而找到值。

    1 #include <stdio.h>
    2 int main() {
    3     int num[] = {0,1,2,3,4,5,6,7,8,9};
    4     int *p = &num[0];
    5     for(int i=0 ;i<10;i++,p++){
    6         printf("%d
    ",*p);  
    7     }
    8     return 0;
    9 }
    例子

    数组的指针偏移1表示指针往右边移动了一个类型,例如:int的类型加1等于指针地址加上了4个字节。

    指针通过循环输出了数组所有的元素,然后指针本身就变成了一个野指针。我们可以通过过:野指针-数组名 =数组的个数(也可以说是指针的偏移量)

    函数传入数组

    数组做函数参数,说具体是指向数组的指针变量做函数参数。 
    由于数组名是该数组的首地址,指针变量的值也是首地址,所以函数的实参和形参都可以指向数组名或者数组的指针。于是有了以下四种对应关系:

    例子:

     1 #include <stdio.h>
     2 int main()
     3 {
     4     float ave(int *b, float num);   //这里的是声明函数
     5     int counter,a[5] = {0};
     6     float all =0, res;
     7 
     8     scanf("%f", &all);
     9     for(counter = 0; counter < all; counter++)
    10     {
    11         scanf("%d", &a[counter]);
    12     }
    13     res = ave(a, all);  //这里把数组的名字传入了函数定义的指针变量。和输入第一次输入的次数
    14     printf("%f", res);
    15     return 0;
    16 }
    17 
    18 float ave(int *b, float num)   //这里和上面声明函数一样
    19 {
    20     int i, sum =0;
    21     float ave;
    22     for(i = 0; i < num; i++)
    23     {
    24         sum = sum + b[i];
    25     }
    26     ave = (float)sum/num;
    27     return ave;
    28 }

    这里传入函数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的输出可以是字符串的地址,而不需要解引用。

    输出字符串有三种方法,如下所示。

    1 #include <stdio.h>
    2 int main(){
    3     char ch1[] ="luotianyi";    //第一种是用数组的方式输出字符串
    4     printf("%s
    ",ch1);
    5     char *ch2 = "luotianyi";    //第二种是利用指针变量保存字符串
    6     printf("%s
    ",ch2);
    7     printf("luotianyi");       //第三种是直接用把字符串放到printf中
    8     return 0;
    9 }

    这三种方法有2个区别,第一种利用数组的方式存储是把字符串存储在栈中(也就是可以进行修改的地方,也可以进行输出)。第二种和第三种是保存在堆中的(也就是只能输出,但是不允许进行修改)。

     1 #include <stdio.h>
     2 int main(){
     3     char ch1[] ="luotianyi";
     4     ch1[1] = 'w';   //可以进行修改
     5     printf("%s
    ",ch1);
     6     char *ch2 = "luotianyi";
     7     *ch2+1 = 's';    //error: lvalue required as left operand of assignment
     8     printf("%s
    ",ch2);
     9     printf("luotianyi");
    10     return 0;
    11 }

    下面我们看看字符串是如何传入函数中的,我们分别演示下用指针变量和数组变量进行。

     1 #include <stdio.h>
     2 int main(){
     3     char str1[] = "luotianyi";
     4     char* str2 = "my wife";
     5     int strpri(char ch1[],char* ch2) ;
     6     strpri(str1,str2);
     7     return 0;
     8 }
     9 int strpri(char ch1[],char* ch2){   //我们分别用两种方法传入
    10     char* tmp;  //创建一个指针对其进行转换
    11     tmp = ch1;
    12     ch1 = ch2;
    13     ch2 = tmp;
    14     ch2[3] = 'z';
    15     printf("%s
    ",ch1);     //在这里可以看出指针变量所指向的字符串内部虽然不可以改变,但是可以对其整体进行其他的操作。
    16                             //也就是说字符串单个字符的操作是不可以的,但是可以对其整体进行操作
    17     printf("%s
    ",ch2);         //这里可以看出我们可以对数组变量的字符串进行操作
    18     return 0;
    19 }
    例子

    堆与栈的区别还有就是栈可以保存多份一样的值,而堆只保存一份,其余的也要调用的话就是多个变量都是指向堆的这一份。

     1 #include <stdio.h>
     2 int main(){
     3     char* a = "luotianyi";
     4     char* b = "luotianyi";
     5     printf("%ld
    ",a);
     6     printf("%ld
    ",b);
     7     return 0;
     8 }
     9 /*
    10  * 4299173896
    11  * 4299173896
    12  * */
    堆的示例

    指针字符串 or 数组字符串  

     1 #include <stdio.h>
     2 int main(){
     3     char* ch[] = {"luotianyi","wsj","woaini"};    //这就是创建一个数组字符串或是叫做指针字符串
     4     for (int i = 0; i < 3; ++i) {
     5         printf("%s
    ",ch[i]);   //输出全部
     6     }
     7     printf("%c
    ",ch[1][2]);    //第一个下标是第几排,第二个是低级列
     8     printf("%c
    ",*(*(ch+1)+1));  //外面的数字是第几横排,里面的是横排的第几个数字
     9     return 0;
    10 }


    ---------------------
    部分来源和代码出自以下链接
    来源:CSDN
    原文:https://blog.csdn.net/C2681595858/article/details/53750577
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    订单的处理原理及代码实现.
    购物车的原理及实现.(仿京东实现原理)
    集群下session共享问题的解决方案.
    页面静态化技术Freemarker技术的介绍及使用实例.
    ActiveMQ的介绍及使用实例.
    获取Android运行apk的packagename 和activityname
    linux extundelete 删除文件恢复
    jenkins 批量修改配置文件
    jenkins构建自动执行jmeter 发送http请求,中间有替换参数路径
    jenkins 执行ssh 远程linux执行命令
  • 原文地址:https://www.cnblogs.com/luotianyi520/p/9862292.html
Copyright © 2020-2023  润新知