(二)数组、指针、函数

来源:互联网 发布:非农数据对美元影响 编辑:程序博客网 时间:2024/06/06 08:38

一、数组

    1、一维数组

        1》定义

        2》初始化

        3》使用

        4》存储

    2、多维数组

        1》定义

        2》初始化

        3》使用

        4》存储

    3、变长数组

    4、数组传参

        地址传递:传数组名和元素个数

#include <stdio.h>//void fun(int n,int b[])void fun(int n,int *b){int i;for(i = 0; i < n; i++)printf("%d\t",b[i]);printf("\n");}int main(void){int a[5] = {1,2,3,4,5};fun(5,a);return 0;}

#include <stdio.h>//void fun(int n,int m, b[][m])void fun(int n,int m, int (*b)[m]){int i,j;for(i = 0; i < n; i++){for(j = 0; j < m; j++)printf("%d\t",b[i][j]);printf("\n");}}int main(void){int a[2][3] = {{1,2,3},{4,5,6}};fun(2,3,a);return 0;}

二、指针

    1、概念:

在C语言中,内存单元的地址称为指针,专门用来存放地址的变量,称为指针变量(pointervariable), 在不影响理解的情况中,有时对地址指针指针变量不区分,通称指针

    2、指针三要素:

       当给一个指针初始化或者赋值之后,则该指针存在三要素,例如:

           int a = 100;

           int *pa = &a;

       此时,对于pa来说,有以下三个表达式:

           *p  表示p指向的数据

           p   表示p的内容

           &p  表示变量p在内存中的地址

    3、指针的运算:

       1》赋值: =

       2》取值:*

       3》取地址:&

       4》加法运算:+

            只能加一个整数

       5》减法运算:-

            可以减一个整数

            也可以两个同类型的指针相减

        6》关系运算:> < >= <= == !=

            表示地址高低的比较

    4、const关键字

    5、多级指针

        在C语言中,把存储指针变量地址的变量,称为多级指针变量,简称多级指针。

        int a = 100;

        int *p1 = &a;    //p1为一级指针

        int**p2  = &p1; //p2为二级指针

        int ***p3 = &p2; //p3为三级指针

        综上:n级指针变量中可以存放n-1级指针变量的地址。

#include <stdio.h>int main(void){int a = 100;int *p1 = &a;  //p1为一级指针int **p2  = &p1;//p2为二级指针int ***p3 = &p2;//p3为三级指针printf("a = %d\n",a);printf("*p1 = %d\n",*p1);printf("**p2 = %d\n",**p2);printf("***p3 = %d\n",***p3);return 0;}


6、void关键字

        1》修饰函数返回值

            表示该函数没有返回值

        2》修饰函数的参数

            表示该函数没有参数

        3》定义指针

            表示该指针中可以存放任何类型的地址,通常我把它称为通用指针。

#include <stdio.h>int main(void){void *p;int a = 100;p = &a;printf("a : %d\n",a);printf("*p : %d\n",*(int*)p);char b = 'A';p = &b;printf("b : %c\n",b);printf("*p : %c\n",*(char*)p);float c = 3.4;p = &c;printf("c : %f\n",c);printf("*p : %f\n",*(float*)p);return 0;}

三、指针和数组的关系:

    1、指针可以指向一个数组,数组指针

    2、数组中可以存储多个相同类型的地址,指针数组

#include <stdio.h>int main(void){#if 1int a[5] = {1,2,3,4,5};int *b[5] = {a,a+1,a+2,a+3,a+4};int *p = a;int * *pb = b;int i;for(i = 0; i < 5; i++)printf("%d\t%d\n",p[i],*(p+i));for(i = 0; i < 5; i++)printf("%d\t",*pb[i]);printf("\n");#elseint a[2][3] = {{1,2,3},{4,5,6}};int(*p)[3] = a;int i,j;for(i = 0; i < 2; i++)for(j = 0; j < 3; j++)printf("%d\t%d\t%d\n",p[i][j],*(p[i]+j),*(*(p+i)+j));#endifreturn 0;}

3、带参的主函数

#include <stdio.h>/** argc : 命令行参数个数argv : 命令行参数 *///int main(int argc, char *argv[])int main(int argc, char **argv){int i;printf("argc = %d\n",argc);for(i = 0; i < argc; i++)printf("%s\n",argv[i]);return 0;}

四、函数

    1、基本概念

        1》函数的定义

        2》函数的声明

        3》函数的调用

        4》实参,形参及它们的关系

    2、函数传参

        1》传参方式:

            1)值传递:

                在被调用函数中不能改变实参

                实参类型和形参类型相同

            2)地址传递

                在被调用函数中可以改变实参

                形参类型是实参类型对应的指针类型

        2》根据实参的类型可以将传参分为以下几种

            1)实参是常量

                值传递

            2)实参是基本类型变量

                值传递

                地址传递

            3)实参是数组

                地址传递:传数组名和元素个数

            4)实参是指针变量

                值传递:

#include <stdio.h>void fun1(int *p1,int *p2){int *t,b;//不能改变实参的值t = p1;p1 = p2;p2 = t;//可以改变实参指向的数据b = *p1;*p1 = *p2;*p2 = b;}void fun2(int **p1,int **p2){#if 0int *t;//可以改变实参的值t = *p1;*p1 = *p2;*p2 = t;#else//实参指向的数据也可义改变int b;b = **p1;**p1 = **p2;**p2 = b;#endif}int main(int argc, char **argv){int a = 3,b = 5;int *pa = &a, *pb = &b;#if 0printf("pa = %p,pb = %p\n",pa,pb);printf("a = %d\t,b = %d\n",a,b);fun1(pa,pb);  //值传递,在被调用函数中不能改变pa和pbprintf("pa = %p,pb = %p\n",pa,pb);printf("a = %d\t,b = %d\n",a,b);#endif#if 1printf("pa = %p,pb = %p\n",pa,pb);printf("a = %d\t,b = %d\n",a,b);fun2(&pa,&pb);//地址传递,在被调用函数中可以改变pa和pbprintf("pa = %p,pb = %p\n",pa,pb);printf("a = %d\t,b = %d\n",a,b);#endifreturn 0;}

3) 返回函数的地址

4)返回值字符型指针

#include <stdio.h>int fun1(void){int x = 123;return x;}char * fun2(void){return "hello world";}int *fun3(int n,int a[]){int i;for(i = 0; i < n; i++)a[i] *= 2;return a;}void fun(void){printf("hello world\n");}typedef void(*TYPE)(void);//void(*fun4(void))(void)TYPE fun4(void){return fun;}char *fun5(void){//char p[] = "hello world";   //p不能返回char *p = "hello world";//p可以返回return p;}int main(int argc, char **argv){#if 1char *str;str = fun5();printf("%s\n",str);#elsevoid (*p)(void);p = fun4();p();int arr[5] = {1,2,3,4,5};int *p,i;for(i = 0; i < 5; i++)printf("%d\t",arr[i]);printf("\n");p = fun3(5,arr);for(i = 0; i < 5; i++)printf("%d\t",arr[i]);printf("\n");#endifreturn 0;}

通用行Makefile,在当前目录下需要生成多个可执行文件是直接make,同时根据时间戳分别一一生成对应文件名的可执行文件

CC = gccCFLAGS = -Wall -g -O0#wildcard 执行make时,将当前目录下所有*.c的文件名赋给SRCSRC = ${wildcard *.c}#patsubst 根据第一个参数,在第三个参数中匹配对应的文件名,匹配成功则将其转换成第二个参数的格式OBJS = ${patsubst %.c,%,$(SRC)}#all为伪目标all:$(OBJS)%:%.c$(CC) -o $@ $^     clean:$(RM) $(OBJS)