Fork me on GitHub

C语言学习之指针、数组和函数那点事儿

函数、数组和指针

书中示例:编写一个处理数组的函数,要求该函数能够返回数组中所有元素之和。

 total=sum(marbles);

这里的marbles为数组名,表示首元素的地址
注意:
除了以下两种情况数组名表示的不是首元素地址,其余都是:
1、&数组名 数组名不是首元素的地址,表示整个数组。&数组名:取出的是整个数组的地址
2、sizeof(数组名) 数组名表示整个数组 sizeof(数组名)

所以既然能用数组名表示地址,那么也能用数组名表示指针。

上代码:

 #include <stdio.h>
 #define SIZE 10
 int sum(int* ar, int n);
 int main(void)
 {
 int marbles[SIZE] = { 20, 10, 5, 39, 4, 16, 19, 26, 31, 20 };
 long answer;

 answer = sum(marbles, SIZE);
 printf("The total number of marbles is %ld.\n", answer);
 printf("The size of marbles is %zd bytes.\n",
     sizeof marbles);

 return 0;
 }

 int sum(int* ar, int n)
 {
 int i;
 int total = 0;

 for (i = 0; i < n; i++)
     total += *(ar+i);
 printf("The size of ar is %zd bytes.\n", sizeof ar);

 return total;
 }

另一类写法

 #include <stdio.h>
 #define SIZE 10
 int sum(int ar[], int n);
 int main(void)
 {
 int marbles[SIZE] = { 20, 10, 5, 39, 4, 16, 19, 26, 31, 20 };
 long answer;

 answer = sum(marbles, SIZE);
 printf("The total number of marbles is %ld.\n", answer);
 printf("The size of marbles is %zd bytes.\n", sizeof marbles);

 return 0;
 }

 int sum(int ar[], int n)
 {
 int i;
 int total = 0;

 for (i = 0; i < n; i++)
 total += ar[i];
 printf("The size of ar is %zd bytes.\n", sizeof ar);

 return total;
 }

显然,运行后效果是一样的,所以int* ar能表示为int ar[]
运行结果显示,ar的大小为8字节,即在该系统中用于存储地址的内存大小为8字节
两个重要的符号:
strien是求字符串长度的,只针对字符串长度,是一种库函数,使用时必须引用头文件
sizeof计算变量、数组类型的,大小单位是字节,是一种操作符

使用指针形参

函数处理数组时必须知道何时开始,何时结束
第一种表达方式是用一个指针形参标识数组的开始,用一个整数形参表明待处理的元素个数

 int sum(int* ar, int n);
 answer = sum(marbles, SIZE);

第二种表达方式是分别使用一个指针形参标识数组的开始,一个指针形参指明数组的结束处

 int sump(int * start, int * end);
 answer = sump(marbles, marbles + SIZE);//结束处指向数组最后一个元素的后面

所以上例也可以写成:

 #include <stdio.h>
 #define SIZE 10
 int sump(int * start, int * end);
 int main(void)
 {
 int marbles[SIZE] = { 20, 10, 5, 39, 4, 16, 19, 26, 31, 20 };
 long answer;

 answer = sump(marbles, marbles + SIZE);
 printf("The total number of marbles is %ld.\n", answer);

 return 0;
 }

 int sump(int * start, int * end)
 {
 int total = 0;

 while (start < end)
 {
      total += *start;    // 使用*解引用,再把数组元素的值加起来
      start++;            // 让指针指向下一个元素
 }

 return total;
 }

由于一元运算符*和++的优先级与++的优先级相同,所以根据结合律从右往左的规则,所以也可以写成:

 total += *star++;//先把指针指向位置上的值加到total上,然后再递增指针

后缀的位置影响十分大,上代码:

 #include <stdio.h>
 int data[2] = { 100, 200 };
 int moredata[2] = { 300, 400 };
 int main(void)
 {
 int * p1, *p2, *p3;

 p1 = p2 = data;
 p3 = moredata;
 printf("  *p1 = %d,   *p2 = %d,     *p3 = %d\n",*p1, *p2, *p3);
 printf("*p1++ = %d, *++p2 = %d, (*p3)++ = %d\n",*p1++, *++p2, (*p3)++);
 printf("  *p1 = %d,   *p2 = %d,     *p3 = %d\n",*p1, *p2, *p3);

 return 0;
 }

运行结果是;

 *p1 = 100,      *p2 = 100,        *p3 = 300
 *p1++ = 100,    *++p2 = 200,    (*p3)++ = 300
 *p1 = 200,      *p2 = 200,        *p3 = 301

总结出其中规律就是:

 *p++:先使用指针指向位置上的值,然后再递增指针
 *++p:先递增指针,再使用递增指针指向位置上的值
 (*p)++:先使用指针指向位置的值,再将该值递增  

指针表示法与数组表示法

由以上例子分析可以看出,处理数组的函数实际使用的是指针作为实参,而函数的编写可以选择使用两种表示法。只不过使用数组表示法的意图会更加明显
在C语言中,ar[i]与(*ar+1)是等价的,只不过当ar为指针变量时,才使用ar++这样的表达式
指针表示法(尤其是与递增运算符一起使用时)更加接近机器语言,因此一些编译器在编译时能生成效率更高的代码

指针操作

八种操作:

 #include <stdio.h>
 int main(void)
 {
 int urn[5] = { 100, 200, 300, 400, 500 };
 int * ptr1, *ptr2, *ptr3;

 ptr1 = urn;            // 把一个地址赋给指针
 ptr2 = &urn[2];        // 把一个地址赋给指针
                        // 解引用指针,以及获得指针的地址
 printf("pointer value, dereferenced pointer, pointer address:\n");
 printf("ptr1 = %p, *ptr1 =%d, &ptr1 = %p\n", ptr1, *ptr1, &ptr1);

 // 指针加法
 ptr3 = ptr1 + 4;
 printf("\nadding an int to a pointer:\n");
 printf("ptr1 + 4 = %p, *(ptr1 + 4) = %d\n", ptr1 + 4, *(ptr1 + 4));
 ptr1++;                // 递增指针
 printf("\nvalues after ptr1++:\n");
 printf("ptr1 = %p, *ptr1 =%d, &ptr1 = %p\n", ptr1, *ptr1, &ptr1);
 ptr2--;                // 递减指针
 printf("\nvalues after --ptr2:\n");
 printf("ptr2 = %p, *ptr2 = %d, &ptr2 = %p\n", ptr2, *ptr2, &ptr2);
 --ptr1;                // 恢复为初始值
 ++ptr2;                // 恢复为初始值
 printf("\nPointers reset to original values:\n");
 printf("ptr1 = %p, ptr2 = %p\n", ptr1, ptr2);
 // 一个指针减去另一个指针
 printf("\nsubtracting one pointer from another:\n");
 printf("ptr2 = %p, ptr1 = %p, ptr2 - ptr1 = %td\n", ptr2, ptr1, ptr2 - ptr1);
 // 一个指针减去一个整数
 printf("\nsubtracting an int from a pointer:\n");
 printf("ptr3 = %p, ptr3 - 2 = %p\n", ptr3, ptr3 - 2);

 return 0;
 }

指针函数

指针函数:返回指针类型的函数

char*getWork(char C){
switch(c){
    case'A':return "Apple";
    case'B':return "Banana";
    case'C':return "Cat";
    case'D':return "Dog";
    default:return "None";
    }
}

int main(void){
char input;
printf("please input a charactar:");
input=getchar();
printf("%c\n", input);
printf("%s\n", getWord(input));
getchar();
return 0;
}

另一种十分类似的写法(但这种写法是不对的):

char*getWork(char C){
{
    char str1[]="Apple";
    char str2[]="Banana";
    char str3[]="Cat";
    char str4[]="Dog";
    char str5[]="None";
switch(c){
    case'A':return str1;
    case'B':return str2;
    case'C':return str3;
    case'D':return str4;
    default:return str5;
    }
}

int main(void){
char input;
printf("please input a charactar:");
input=getchar();
printf("%c\n", input);
printf("%s\n", getWord(input));
getchar();
return 0;
}

不要返回局部变量的指针(数组)
在该例中,str1是局部变量,这个字符数组在子程序结束后,它对应的存储空间会立即释放

函数指针

函数指针:指向函数起始地址的指针
函数指针定义:
函数返回类型名(指针变量名)(函数形参类型列表)
如:int(
fptr)(int,int);
指针函数的使用:
1、指针变量名=被指向函数名;
如:fptr=maxx;
2、函数调用:指针变量名(函数调用时的实际参数);
如:int x=fptr(5,8);

看不懂?上代码:

#include<stdio.h>
int square(int num){
return num*num;
}
int main(void){
int num;
int(*fp)(int);
printf("please input a number:");
scanf_s("%d", &num);
fp=square;//建立联系
printf("fp=0x%x, %d\n",fp,(*fp)(num));//调用*fp指向的函数并传入num这一实参
return 0;
}

函数名等于函数的地址。通过fp=square;语句使得fp指向函数的入口,因此通过fp指针就能找到函数squar的代码存放的位置,从而调用并执行这段代码。

posted @   硫酸钠  阅读(125)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示