翁恺 程序设计入门C语言笔记-数组与指针

数组
const int number = 10;
int x,i;
int count[number];    //给数组的下标确定一个常值的变量,方便修改和让人清晰的看懂程序,如果都写10就较难看懂每个10之间到底是不是表达的同一个意思。

//初始化数组
for (i=0;i<number;i++){
    count[i]=0
}
scanf("%d",&x);
while( x! = -1){
    if (x>=0 && x<=9){
        count[x]++;   //输入0-9的任意个数的数字,并且记录输入的个数
    }
    scanf("%d",&x);
}

//遍历数组输出
for (i=0;i<number;i++){
    printf("%d:%d\n",i,count[i]);
}
指针
  • 取地址符,& 取一个变量的地址,操作数只能是是地址。
int i;
printf("%p",&i);    //要输出地址以 %p
//地址不是真的整数,所以用%d或者将地址直接赋值给一个int 类型的变量可能会出错
&(++i);   &(a+b);  //都是错误的,因为取地址只能取一个变量而不是一个表达式
printf("%d",*p);   //*p作为一个整体可以看作是一个变量,就是指针指向变量的类型
//正确的定义指针的方式
int* p =&i;    //p是一个指针,指向的是int类型的变量,值就是指向的变量的地址
int *p;  //同上
int* p,q; //p是一个指针,q只是一个整数,*其实是加给p的,并不是说有int*这个类型
int *p,q;  //同上

//综上,一个指针p,p的值是指向变量的地址,&i,而*p的值是指向变量的值
  • 参数中传入的数组就是指针

    int a[] = {1,2,3,4,};
    test(int a[]);   
    test(a);   //将a[]当参数传递到test中去,实际上传递的是指向a的指针
    //当我们在函数中进行操作
    test(int a[]){
        a[0]=1000;
    }
    //进入函数后,a[0]就会被修改为1000,退出函数后a[0]还是1000,因为是通过指向数组的指针直接作用到a[0]修改了值。
    
    test(int* a);   //也可以写成这样,因为传入数组就是传递指针
    

    数组变量本身表达地址,是一种特殊的指针,,是const类型的指针,const表示常量,在初始值赋值以后不能改变他的值了

    数组的单元表达的是变量,需要用取地址

    int a[10]; int* p=a;  //a就是一种指针
    int* p = &a[0]   //数组的单元是一个变量
    
  • 指针的运用

    • 在函数中返回多个值

    因为函数只能return一个值,所以需要返回多个值时,如交换两个数,找出一个数组中的最大值就需要用到指针,将指针设为参数

    • 函数返回运算的状态,结果通过指针返回
    int divide(int a,int b,int *result);
    
    int main(void)
    {
        int a = 5;
        int b = 2;
        int c;
        if ( divide(a,b,&c) ){
            printf("%D/%d=%d\n",a,b,c);
        }
        return 0;
    }
    int divide(int a,int b,int *result){
        int ret = 1;  //返回值为1时表示没有出错,方便对if进行运算
        if ( b == 0) ret = 0;(如果除数为0,就会出错)
        else{
            *result = a/b;    //将结果由result返回
        }
        return ret;
    }
    
  • 函数指针

void f(void)
{
    
}

int main ()
{
    void (*pf)(void) = f;    //f是函数f的地址,这里定义了一个指向f函数的指针
    printf("%p\n",pf);     //输出函数的地址
    
    //可以通过函数指针来  调用函数  
    (*pf)();    
}

函数指针作用:

  • 代替 switch case语句,方便拓展
void g(int i)
{
    printf("int g(), %d\n",i);
}

void f(int i)
{
    printf("int f(), %d\n",i);
}

int main(void)
{
    int i = 0;
    scanf("%d",&i);
    switch(i)
    {
        case 0:f(0);break;
        case 1:g(1);break;   
    }
    return 0;
}

//可以改写为
int main(void)
{
    int i = 0;
    scanf("%d",&i);
    void(*pf[])(int)={g,f};
    if (i >= 0 && i<sizeof(pf)/sizeof(pf[0])){
        (*pf[i])(0);
    } 
    return 0;
}

//这样如果想要增加要调用的函数,只需要在指针里增加另外的函数即可

  • 将函数作为一个参数传入另一个函数中
#include <stdio.h>
#include <stdbool.h>
#include <node.h>
#include <stdlib.h>

int add(int a,int b)
{
    int c=a+b;
    return c;
}

int minus(int a,int b)
{
    int c=a-b;
    return c;
}

void cal(int (*f)(int,int))    //将函数作为参数
{
    printf("%d\n",(*f)(2,3));   //调用函数
}

int main(void)
{
    cal(add);
    cal(minus);   
    return 0;
}
  • 空指针

At the very high level, we can think of NULL as a null pointer which is used in C for various purposes. Some of the most common use cases for NULL are
a) To initialize a pointer variable when that pointer variable isn’t assigned any valid memory address yet.
b) To check for a null pointer before accessing any pointer variable. By doing so, we can perform error handling in pointer related code e.g. dereference pointer variable only if it’s not NULL.(检查指针有关的错误,perform执行,放在条件语句中防止传递一个空指针过去)
c) To pass a null pointer to a function argument when we don’t want to pass any valid memory address.

//The examples of a is
int * pInt = NULL; 

//b
if(pInt != NULL) /*We could use if(pInt) as well*/
{ /*Some code*/} 
else
{ /*Some code*/} 

//c
int fun(int *ptr) 
{ 
 /*Fun specific stuff is done with ptr here*/
 return 10; 
} 
fun(NULL); 

  • 指针安全
int* p;
p = xx;
p == xx;   //当指针出现在表达式的左边的时候,一定要去思考会不会为NULL,要判断一下,如果为NULL是非法的语句

一个返回本地变量地址的指针是危险的。因为本地变量的内存出了函数以后就被释放掉了,这个内存就会被别的变量使用。

返回全局变量或者是静态本地变量是安全的,?但是使用这两个的函数是线程不安全的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值