C_Language_09

C_Language_09

    1.程序运行时,系统会为数据分配内存单元,存储数据
    2.内存是由多个连续的内存单元组成,内存单元用于存储数据,
     每个内存单元占1个字节,1个字节==8个二进制位
    内存单元地址:内存单元的编号,连续的。便于访问内存单元,就像门牌号一样
    3.数据如何存储:字节是最小的内存单元,一个字节称为一个存储单元,即内存单元,不同的数据类型所占的存储单元不等,为了正确访问内存单元,每个内存单元都有一个编号,内存单元的编号称作地址,内存单元中的内存就是我们存储的数据。
    4.访问数据的两种方:
      1)直接访问:定义变量存储数据,通过变量名访问数据
    int a = 10;
    int b = a;//通过变量a访问内存中的数据
      2)间接访问:通过内存单元地址,访问内存中的数据,任何数值都是存储在内存中的存储单元中
    5.内存单元的地址,被称为指针
      指针变量:存储指针(地址)的变量
      定义一个指针变量
    int *p = NULL;// 整型指针
    float *q = NULL;// 浮点型指针
    char *r = NULL;// 字符型指针
    NULL是空指针,相当于0,NULL是给指针变量赋值的
    定义指针变量的语法
    int c = 20;
    类型修饰符 * 指针变量名 = 初始值(地址)
    *表示:定义的变量是一个指针变量,存储的内容是地址
    类型修饰符表示:地址指向的存储单元中数据的类型(即通过地址找到的数据类型)
    指针变量的类型:类型修饰符 * 指向某种类型数据的指针类型
    p的类型 int * 指向整型数据的指针类型
    q的类型 float * 指向浮点型数据的指针类型
    r的类型 char * 指向字符型数据的指针类型
    指针变量通常被称为指针

    通过指针访问存储单元,必须先获取存储单元的地址
    取地址运算符 & 获取变量的地址
    输出地址格式符 %p
    int a = 100;
    printf("变量a的存储单元地址:%p\n",&a);
    float b = 1.5;
    printf("变量b的存储单元地址:%p\n",&b);
    char c = 'a';
    printf("变量c的存储单元地址:%p\n",&c);
    printf("---------------------------\n");

    定义指针存储地址
    要求:指针类型修饰符 和 指向的变量的类型必须一致
    int *p = &a;//指针p指向变量a的存储单元(指针p中存储的地址是变量a的存储单元地址)
    printf("指针p的存储的地址:%p\n",p);
    float *q = &b;
    printf("指针p的存储的地址:%p\n",q);
    char *r = &c;
    printf("指针p的存储的地址:%p\n",r);
    通过指针访问存储单元
    访问变量的存储单元的值
    printf("%d\n",*p);//*p获取p指向的内存地址中的值
    printf("%f\n",*q);
    printf("%c\n",*r);
    int i = *p;//i = a ;
    float j = *q;//j = b;
    char k = *r;//k = c;
    printf("%d\n",i);
    printf("%f\n",j);
    printf("%c\n",k);
    printf("---------------------------\n");

    使用修改数
    a = 200;
    b = 2.5;
    c = 'f';
    printf("a = %d *p = %d \n",a,*p);
    使用指针修改数据
    *p = 300;
    *q = 3.5;
    *r = 't';
    printf("a = %d *p = %d\n",a,*p);

    & 和 * 是配套使用的,互为逆运算
    & 获取变量存储单元地址
    * 通过地址访问变量的存储单元
    练习
    int x = 0;
    int y = 0;
    int *m = NULL;//指针m指向空指针位置
    m = &x;//指针m 重新指向变量x
    *m = 10;//通过m存储的地址访问变量x的存储单元,都取x的值
    printf("x = %d\n",*m);
    m = &y;
    *m = 20;
    printf("y = %d\n",*m);

    指针的存储空间与操作系统有关
    32位操作系统中占4个字节,64位操作系统中占8个字节
    printf("%lu\n",sizeof(m));

    区分指针中的 * 的作用
    1.如果是在定义指针变量的时候, int *p = NULL;这个*代表的是p是一个指针变量
    2.如果定义完成再使用 *p 的时候,* 表示的时取出p指向的地址里面的数据

    指针的运算
    指针只有加、减运算
    定义指针时的类型,决定指针移动几个字节

    第一种:p+n
    表示:从p指向的存储单元向高位偏移n个数据类型的字节数(n * 数据类型的字节数)
    int a = 100;
    int *p = &a;
    printf("%p\n",p);
    printf("%p\n",p+1);
    printf("%p\n",p+2);
    第二种:p - n
    表示:从p 指向的存储单元向低位偏移n个数据类型的字节数(n * 数据类型的字节数
    第三种:p++ 或 ++p 指针向高地址移动,移动的距离是指针指向数据类型所占的字节数
    p的指向改变了
    int a1 = 200;
    p = &a1;
    printf("%p\n",p);
    p++;
    printf("%p\n",p);
    ++p;
    printf("%p\n",p);
    int a1 = 6;
    int *i = &a1;
    printf("%p",i);

指针与数组:
    1.定义一个数组
    int a[5] = {1,2,3,4,5};
    2.访问数组元素 数组名[下标]
    a[0] = 10;
    printf("%d\n",a[0]);
    3.计算数组元素个数
    printf("%lu\n",sizeof(a));
    printf("%lu\n",sizeof(int));
    printf("%lu\n",sizeof(a[0]));
    printf("%lu\n",sizeof(a)/sizeof(int));
    printf("%lu\n",sizeof(a)/sizeof(a[0]));
    4. 数组名是常量,表示数组元素的地址 a = &a[0]
    指针可以指向变量,读取变量存储单元中的值
    指针可以指向数组元素,数组在内存中是一段连续的存储空间,每个元素都占有相应的存储单元
    数组元素的指针即数组元素的地址
    访问数组元素可以使用数组名或者指向数组的指针
    访问数组元素的两种方式:下标法,指针法
    1.下标法
    int *p = a;//数组名是常量,表示数组首元素的地址&a[0],此时,p指向数组第一个元素的存储单元,表示首元素地址
    printf("%p\n",&a[0]);
    printf("%p\n",a);
    printf("%p\n",p);
    使用数组名
    printf("%d %d\n",a[0],a[1]);
    使用指针
    printf("%d %d\n",p[0],p[1]);
    printf("%d %d\n",*p,*(p+1));
    for (int i = 0; i < 5; i++) {
        printf("%d ",p[i]);
    }
    printf("\n");
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4-i; j++) {
            if (p[j] < p[j+1]) {
                int t = p[j];
                p[j] = p[j+1];
                p[j+1] = t;
            }
        }
    }
    for (int i = 0; i < 5; i++) {
        printf("%d ",p[i]);
    }
    printf("\n");

    2.修改指针指向 不能使用数组名 只能使用指针
    printf("%d\n",*p);//指向a[0]
    printf("%d\n",*(++p));
    printf("%d\n",*(p++));
    printf("%d\n",*++p);// ++ 的优先级高于 *
    修改
    int b[5] = {1,3,5,7,9};
    int *q = b;
    b[1] = 20;
    q[1] = 10;
    *(q+1) = 10;
    *(b+1) = 20;
    for (int i = 0; i < 5; i++) {
        printf("%d ",b[i]);
    }
    printf("\n");
    printf("-------------------------\n");

    for (int i = 0; i < 5; i++) {
        printf("%p\n",q+i);
    }
    printf("%d\n",b[0]);//数组的第一个元素
    printf("%d\n",q[0]);//数组的第一个元素
    printf("%d\n",*q);//数组的第一个元素
    printf("%d\n",*(q+1));//数组的第二个元素
    printf("%p\n",b);//数组首地址
    printf("%p\n",b+1);//数组第二个元素地址
    printf("%p\n",q);//数组首地址
    printf("%p\n",q+1);//数组第二个元素地址
    printf("%d\n",*q+1);//数组第一个元素值加1
    printf("%p\n",&b);//数组首地址
    printf("%p\n",&b+1);//偏移整个数组的大小

指针和数组的区别:
    指针和数组都可以通过下标法和指针法访问数组元素
    1.指针可以修改指向
      数组名是 常量 ,表示首元素的地址,不能改变
    2.指针的存储空间:4/8字节
      数组的存储空间:元素个数*元素的存储空间
    3.sizeof(数组名) 得到的是数组的存储空间
      sizeof(指针)得到的时4/8字节,不管指针指向的存储空间存储的是哪种数据
    printf("-------------------------\n");
    char a11[3] = {'a','b','c'};
    char *f = a11;
    printf("%lu\n",sizeof(f));
    printf("%lu\n",sizeof(a11));
    int a[5] = {1,2,3,4,5};
    int *p = a;
    printf("%lu\n",sizeof(a)/sizeof(int));
    printf("%lu\n",sizeof(p)/sizeof(int));

    指针类型和数组元素类型不匹配会怎样?
    short a1[4] = {6,7,8,9};
    int *p1 = a1;
    printf("%d\n",*p1);

指针与字符串:
    定义字符数组存储字符串,str在栈区存放,常量字符串拷贝的副本存储在字符数组中,数组中的元素是可以改变的
    char str[] = "hello";
    char *p = str;
//    使用指针修改数组元素
    *p = 'a';
//    使用指针访问数组元素
    for (int i = 0; i < 6; i++){
        printf("%c ",*(p+i));
    }
    printf("\n");
//    使用指针操作字符串
    printf("%s\n",p);

定义字符指针指向字符串:
    “” 常量字符串,存储在常量区,只能访问不能修改
    定义指针指向常量区的字符串常量的首地址,指针p中只是存储地址
    char *p = "hello";
//    *p = 'a';
//    可以访问字符和字符串
    printf("%s",p);
    printf("%c\n",*p);

总结:指向数组的指针可以访问和修改数组元素;
          指向常量字符串的指针只能访问不能修改。
示例:通过指针可以计算字符串的⻓长度。
int main(int argc, const char * argv[]){
    char str[] = "iphone";
    char *p = str;
    int n = 0;
    while (p[n] != '\0') {
        n++;
    }
    printf("%lu\n",sizeof(str));
    printf("%d\n",n);
    return 0;
}

指针数组:
    二维数组存储字符串 数组的数组
    char str[3][5] = {"ios","ipad","iMac"};
    strs存储的数组元素是字符数组(字符数组中存储的是字符串,常量字符串的副本)
    printf("%s\n",strs[0]);//第一个字符数组的首元素地址,可以访问字符数组
    printf("%s\n",str[1]);
    printf("%s\n",str[2]);
    strcpy(str[0], "mac");
    printf("%s\n",str[0]);
    指针数组 数组中的元素都是指针
    char *strs[3] = {"ios","ipad","iMac"};
    strs 本质是一维数组
    strs 存储的数组元素是字符指针(字符指针指向常量字符串)
    strs[0] 第一个字符指针,指向常量区的“ios”
    strs[1] 第二个字符指针,指向常量区的“ipad”
    strs[2] 第三个字符指针,指向常量区的“iMac”
    printf("%s\n",*strs);
    printf("%s\n",*(strs+1));
    printf("%p\n",strs[0]);
    printf("%p\n",strs[1]);
    printf("%p\n",strs[2]);
//    修改
//    char S = 's';
//    char *Symban = &S;
    strs[0] = "Symban";//strs[0]访问的是字符指针,指针的重新指向另一个常量字符串
    printf("%s\n",*strs);
    printf("%p\n",strs);
    printf("%p\n",strs[0]);
    printf("%p\n",strs[1]);
    printf("%p\n",strs[2]);

指针与函数:指针作为函数的参数
       指针作为函数的参数进行传递,可以实现形参的改变作用到实参
void changeValue(int num1,int num2){
    int temp = num1;
    num1 = num2;
    num2 = temp;
}
void changValue1(int *p1,int *p2){
    int temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}
int num1 = 10,num2 = 20;
changeValue(num1, num2);
printf("%d %d\n",num1,num2);
changValue1(&num1, &num2);
printf("%d %d\n",num1,num2);

向函数传递数组的本质:传入数组首元素的地址,可以是数组名或是指针
void func1(int a[],int count){
    for (int i = 0; i < count; i++) {
        printf("%d",*(a+i));
    }
    printf("\n");
}
void func2(int *a,int count){
    for (int i = 0; i < count; i++) {
        printf("%d",*(a+i));
    }
    printf("\n");
}
int a[] = {1,2,3,4,5};
func1(a, 5);
 字符指针作为形参
func2(a, 5);
 字符指针作为实参
int *p = a;
func1(p, 5);
func2(p, 5);

return 0;
}

posted @ 2015-11-28 14:57  DH_Fantasy  阅读(86)  评论(0)    收藏  举报