C语言基础

来源:互联网 发布:透明头像生成软件 编辑:程序博客网 时间:2024/05/21 08:46

1. 指针定义

指针是一个变量,其值为另一个变量的地址,即内存位置的直接地址。

\\指针声明:

int *ip; // 整型指针

double *ip; // double 型指针

char *ip; // 字符型指针

2. 指针操作

定义指针;把变量地址赋值给指针;访问指针变量中可用地址的值。

eg: 

int var = 20;int *ip;ip = &var;printf("Address of variable: %p\n", &var);printf("Address stored in ip variable: %p\n", ip);  //在指针变量中存储的地址printf("Value of *ip: %p\n", *ip); //使用指针访问值Result:Address of variable: bffd8b3cAddress stored in ip variable: bffd8b3cValue of *ip: 20

NULL--空指针

int *ptr = NULL;printf("ptr 的值是 %p\n", ptr);ptr 的值是 0

大多数操作系统上,程序不允许访问地址为0 的内存,因为该内存是操作系统保留的。然而,内存地址0有特别重要的意义。它表明该指针不指向一个可访问的内存位置。按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。


3. 指针的运算

假设 ptr 为一个指向地址为1000的整型指针,是一个32位的整数,则

ptr++;
执行完上述运算后,ptr指向位置1004,因为ptr每增加一次,它都将指向下一个整数位置,即当前位置往后移4个字节。
若ptr指向一个地址为1000的字符,则该运算会导致指针指向位置1001;
 (1) 指针替代数组
· 递增一个指针
const int MAX = 3;int main(){    int  var[] = {10, 100, 200};    int  i; *ptr;    ptr = var;    for ( i = 0; i < MAX; i++)    {        printf("存储地址:var[%d] = %x\n", i, ptr);        printf("存储值:var[%d] = %d\n", i, *ptr);        ptr++;     }     return 0;}
Result:
存储地址:var[0] = bf882b30;存储值:var[0] = 10;存储地址:var[1] = bf882b34;存储值:var[1] = 100;存储地址:var[2] = bf882b38;存储值:var[2] = 200;
· 递减一个指针
const int MAX = 3;int main(){    int  var[] = {10, 100, 200};    int  i; *ptr;    ptr = &var[MAX - 1];  //指针中最后一个元素的位置;    for ( i = MAX; i > 0; i--)    {        printf("存储地址:var[%d] = %x\n", i-1, ptr);        printf("存储值:var[%d] = %d\n", i-1, *ptr);        ptr--;     }     return 0;}
(2) 指针的比较
比较符号可以用 ==; > ; <
const int MAX = 3;int main(){    int  var[] = {10, 100, 200};    int  i; *ptr;    ptr = var;    i = 0;    while( ptr <= &var[MAX - 1])    {        printf("存储地址:var[%d] = %x\n", i, ptr);        printf("存储值:var[%d] = %d\n", i, *ptr);        ptr++;        i++;     }     return 0;}

3. 函数指针
定义: 指向函数的指针变量。
通常我们所说的指针变量是指向一个整型、字符型或数组等的变量,而函数指针是指向函数。
函数指针可以像一般函数一样,用于调用函数,传递参数。

函数指针变量的声明:

typedef int (*fun_ptr)(int,int);  //声明一个指向同样参数、返回值的函数指针类型

int max(int x, int y){    return x > y ? x : y;}int main(void){    int (*p)(int, int) = & max;  //&可以省略    int a, b, c, d;        printf("请输入三个数字:");    scanf("%d, %d, %d", &a, &b, &c);    d = p(p( a , b ) , c);  //与直接调用等价    printf("最大的数字是: %d\n", d);    return 0;}
Result:
请输入三个数字:1 2 3最大的数字是: 3

回调函数
函数指针作为某个函数的参数
//回调函数void populate_array(int *array, size_t arraySize, int (*getNextValue)(void)){    for (size_t i = 0; i<arraySize; i++)         array[i] = getNextValue();}//获取随机值int getNextRandomValue(void){     return rand();}int main(void){    int myarray[10];    populate_array(myarray, 10, getNextRandomValue);    for(int i = 0; i < 10; i++)   {        printf("%d", myarray[i]);   }    printf("\n");        return 0;}
输出10个随机数。

4. 指向指针的指针
指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。通常一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针包含实际值的位置。
Pointer(address) → Pointer(address) → Variable(value)
一个指向指针的指针变量必须如下声明,即在变量名前放置两个‘ * ’。例如,下面声明了一个指向int类型指针的指针:
int **var;
当一个目标值被一个指针间接指向另一个指针时,访问这个值需要使用两个星号运算符。
int main(){     int var;     int *ptr;     int **pptr;     var = 3000;     ptr = &var;     pptr = &ptr;     printf("Value of var = %d\n", var);     printf("Value available at *ptr = %d\n", *ptr);     printf("Value available at **pptr = %d\n", **pptr);          return 0;}
Result:
Value of var = 3000;Value available at *ptr = 3000;Value available at **pptr = 3000;

5. 传递指针给函数
c 语言允许传递指针给函数,只需要简单地声明函数参数为指针类型即可。
下面的实例中,我们传递一个无符号的long型指针给函数,并在函数内改变这个值:

void getSeconds(unsigned long *par);int main(){     unsigned long sec;          getSeconds( &sec );     printf("Number of seconds: %d\n", sec );       return 0;}void getSeconds(unsigned long *par){      *par = time (NULL);      return;}
Result:
Number of seconds: 1294450468

能接受指针作为参数的函数,也能接受数组作为参数,如下所示:
double getAverage(int *arr, int size);int main(){      int balance[5] = {1000, 2, 3, 17, 50};      double avg;      avg =  getAverage( balance , 5 );      printf("Average value is :%f\n", avg);      return 0;}double getAverage(int *arr, int size){      int i, sum = 0;      double avg;      for ( i = 0; i < size ; i++)      {            sum += arr[i];       }       avg = (double)sum / size;       return avg;}
Result:
Average value is : 214.40000

对于一维数组来说,数组作为函数参数传递,实际上传递了一个指向数组的指针,在c编译器中,当数组名作为函数参数时,在函数体内数组名自动退化为指针。此时调用函数时,相当于传址,而不是传值,会改变数组元素的值。

对于高维数组来说,可以用二维数组名作为实参或者形参,在被调用函数中对形参数组定义时可以指定所有维数的大小,也可以省略第一维的大小说明

将二维数组当作参数的时候,必须指明所有维数大小或者省略第一维的,但是不能省略第二维或者更高维的大小,这是由编译器原理限制的。


6. 从函数返回指针

c语言允许从函数返回指针。为了做到这点,必须声明一个返回指针的函数, 如下所示:

int *my Function(){      ....}

另外,c不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量。

现在,来看下面的函数,他会生成10个随机数,并使用表示指针的数组名(即第一个数组元素的地址)来返回它们,具体如下:

int *getRandom(){      static int r[10];      int i;      srand( (unsigned)time(NULL) );      for( i = 0; i < 10; ++i)      {             r[i] = rand();             printf("%d\n", r[i]);       }       return r;}int main(){      int *p;      int i;      p = getRandom();      for( i = 0; i < 10 ; ++i)      {             printf("*(p + [%d]) : %d\n", i, *(p + i));       }       return 0;}

Result:

15231980531187214107110830097843049495914213012769309710841232504841069321401604461820149169022*(p + [0]) : 1523198053*(p + [1]) : 1187214107*(p + [2]) : 1108300978*(p + [3]) : 430494959*(p + [4]) : 1421301276*(p + [5]) : 930971084*(p + [6]) : 123250484*(p + [7]) : 106932140*(p + [8]) : 1604461820*(p + [9]) : 149169022
TIPS:1. 区别int *p[4] 和 int (*p)[4]int *p[4]; //定义一个指针数组,该数组中每个元素是一个指针,每个指针指向哪里就需要程序中后续再定义了。int (*p)[4]; //定义一个数组指针,该指针指向含4个元素的一维数组(数组中每个元素是int型)。注:原文基本来源于http://www.runoob.com/cprogramming/c-pointers.html