• 数组和指针


    本节结束。==================================================================

    数组类型:是一个复杂类型;(由数组元素类型和数组长度综合表述)如下;数组类型是:(int []);

    类型的本质是:固定大小内存块的别名。是模具。
    一. 对一维数组 C语言规定: int c[10];

    1.一维数组名:c是数组首元素的地址,c+1步长为 4个字节,一个 int 元素大小。
    &c是整个数组的地址,&c+1步长为40个字节,十个 int 元素大小
    虽然c和&c的值相同,但是他们所代表的步长不同。
    2.数组第i 个元素这样表示:c[i] 或 *(c+i); 给它赋值。c[i] = 5 或 *(c+i) = 5;

    本节结束。==================================================================

    二. 多维数组(int a[3][4])
    1.多维数组名:a是指向一个一维数组 的数组指针,a 的步长为一维的长度(即每次+1都跳一行)(16个字节,四个int元素元素大小)
    2.(a+i)代表是整个第i行的地址,(代表二级指针)
    *(a+i)代表第i行首元素地址 (代表一级指针)
    *(a+i)+j或(&a[i][j])代表第i行第j个元素的地址
    *(*(a+i)+j)或(a[i][j])代表第i行第j个元素的值。

    本节结束。==================================================================

    三.多维数组做函数参数的退化问题
    "数组做函数参数时会退化为指针" 如下代码:sizeof(a) == 4; sizeof(b) == 4;都是一个指针大小,并不是数组大小。
    "只不过每种退化后的数组(为指针)步长可能不同"。
    所有的数据在内存里面都是线性存储的。包括多维数组
    1.一维数组的实参传递(实参把值传给形参):
    int fun(char a[20],int n);(fun是被调函数)
    int fun2(char b[3][4]);
    sizeof(a)的是4个字节; sizeof(a)/sizeof(*a)的是4(因为*a是char型元素,一个字节);
    1)高效
    2)C语言处理a[n]的时候(形参),它没有办法知道n是几,它只知道&a[n](即a的地址)是多少,它的值作为参数传递进去了.

    2. 等价关系:
    数组参数                等效的指针参数
    1)一维数组 char a[30]           指针 char *
    2) 指针数组 char *a[30]            指针的指针 char **a
    3) 二维数组 char a[10][30]         数组的指针 char (*a)[30];

    本节结束。===================================================================

    四.指针的杂点:
    1."指针的本质:指向内存的地址", "没有内存就没有内存地址,没有内存地址就没有指针"。
    2."间接赋值是指针存在的最大意义"。
    3

    1.数据类型的本质:占固定内存大小的别名。 类型就是模具,变量是模具产生的实物
    2.变量的本质:(一段连续)内存空间的别名(是一个门牌号)
    3.数组的内容:如 arr[5]; arr数组空间的首元素的地址, &arr代表的是整个数组的首地址,
    arr+1;数组第二个元素的地址,向下移动四个字节。
    &arr+1;代表向下移动20个字节,也就是一个数组内存空间大小。 &arr和arr的值相同,但 +1 的结果不同,因为他们俩本质上是数据类型不同
    4.指针指向谁,就把谁的地址赋给指针
    5.指针变量和它所指向的内存空间变量是两个不同的概念("不懂")
    6.注意: return不是把内存块 64个字节给return出来,而是把内存块的首地址(内存块标号0X23124)给return出来。
    (如下代码:17行和27行输出的值相同)
    #include <stdio.h>
    #include <string.h>

    char *func1()
    {
    char arr[10];
    strcpy(arr,"sdqwyg");
    printf("arr:%s ",arr);
    printf("&arr:%p ",arr);
    return arr;
    }
    int main(void)
    {
    char *ch = NULL;
    printf("&ch:%p ",ch);

    ch = func1();
    printf("ch:%s ",ch);
    printf("&ch:%p ",ch);
    return 0;
    }

    C提高上课第一天===============================
    1.结构体字节对齐原因:用空间换时间。
    2.操作系统最主要的作用:资源分配。
    3.句柄:结构体变量
    4.野指针的特点:操作野指针本身变量没有任何问题;但是不能操作野指针指向的内存空间
    即可以给指针变量(int *p) p 赋任何地址。如(p = NULL; p = 0xaabb; p = 0x9988;)
    但是不能操作野指针指向的内存空间(大部分情况都是如此)。(*p = 100;*p = "sdb";这种情况不可以)。
    5.冒泡:for(int i = 0; i < n-1; i++)
    for(j = 0;j < n-1-i; j++)
    if(a[j] <a[j+1])
    6.选择:for(int i = 0; i <n-1; i++ )
    for(j = i+ 1; j< n; j++)
    if(a[i] <a[j])
    7.实参数组名,就是数组,sizeof(数组名)就是数组总大小
    形参数组名,就是指针。sizeof(数组名)就是指针大小(每个操作平台大小有区别)。

    C提高第二天=======================================
    1.通过指针 操作指针指向的内存,两个要素
    1)"首地址";2)"步长(由指针指向的空间决定)"
    "指针最重要的意义在于间接赋值"
    2.如果是值传递,(即变量本身传递),形参的任何修改不会影响到实参("数组名除外,因为数组名是数组的首地址")
    形参(被调函数里面的变量);实参(主调函数里面的变量)
    3.如果是址传递,(即变量地址传递),形参的任何修改会影响到实参
    1)地址传递, 2)传参过程中建立形参和实参的指针指向关系 3)被调函数内部通过*间接赋值
    4.指针做函数参数:有输入和输出特性
    1)输入特性:实参的内存已确定,在主调函数分配内存
    2)输出特性:在被调函数分配空间
    5.字符数组初始化:(三种情况)
    1)char str1[] = {'a','b','c','d'};
    printf("str1: %s ",str1); //打印出abcd+乱码,因为数组中没有结束符'';
    2)char str2[100] = {'a','b','c','d'};
    printf("str2: %s ",str2); //打印出abcd;因为这相当于数组部分初始化,有结束符''


    6.通过[]和通过*效果是等价的,都是操作指针所指想的内存,
    int a = 10; int *p = &a; printf("%d, %d ",*p, p[0]);打印效果是一样的

    C提高第三天======================================================
    1. 普通数组(char p[4]);是一个数组,元素是字符。
    指针数组(char *p[4]);是一个数组,元素是指针。
    他们俩的传参:1)"传递":普通数组:func(p,len) "接收" void func(char *p,int len );或者 void func(char p[],int len ); 或者 void func(char p[4],int len );
    2)"传递" 指针数组: func(p,len) "接收" void func(char **p,int len);或者 void func(char *p[],int len); 或者 void func(char *p[4],int len);
    当不确定形参类型时,如果是"值传递":可以把实参的原型放上去,再进行优化或不优化都对。如"指针数组"
    如果是"址传递";需要在实参原型上在加上一个 "*" 号,再进行优化活不优化都对。
    2.指针与数组如果做普通变量;两者有本质有区别。
    指针与数组如果做形参时,两者是等价的。

    3.sprintf的用法: char buf[100];格式化一个字符串,中间带数字0:

    1)字符串自带结束符(不是通过格式化给的); sprintf(buf,"sadddadasads");然后打印内容:printf("%s ",buf);内容为"sadd";
    2)格式化一个字符串,中间带数字0,以%d匹配;因为占四个字节,结束符(''或'0')占一个字节;
    sprintf(buf,"sadd%ddada%dsads%d",0,0,0);printf("%s ",buf); 内容为"sadd0dada0sads0"
    3)格式化一个字符串,中间带数字0,以%c匹配;sprintf(buf,"sadd%cada%csads%c",0,0,0);
    printf("%s ",buf);
    printf("%s ",buf);
    int len = sprintf(buf,"sadd%cada%csads%c",0,0,0);它的返回值很重要:是整个字符串的长度;

    C提高第四天=================================
    1.异或(相同为0,不同为1)的特点:1)自己和自己异或为0;2)一个数每一位和0异或:维持不变
    3)一个数每一位和1异或:取反

    2.左移<<:(左边丢弃,右边补0)。左移n位("无越界情况下"),相当于原数乘以2的n的次方
    右移>>:(右边丢弃,左边补0)。
    3.掩码:通过连续的0和1组成,0X0000110,
    如(0X00ff00),通过掩码可以把某些部位的值改变。

    4.一维数组名:int a[10]; printf("a:%d,a+1:%d ",a,a+1);
    printf("&a:%d,&a+1:%d ",&a,&a+1); 两种打印情况不同
    虽然a和&a的值一样,但他们的数组类型是不一样。
    a:代表首元素地址,第0个元素地址,&a[0],第0个元素是int, +1,就是+4个字节。
    &a:代表整个一维数组的地址,整个数组的长度;


    数组类型

    5."指针数组":是一个数组,每个元素都是指针。 int *p[10];
    "数组指针":是一个指针,指向数组的指针。 int (*p)[10];
    有"typedef"是类型,没有"typedef"是变量
    定义数组指针的三种方式:
    1)先定义数组类型,再根据数组类型定义指针变量(不常用)
    int a[10] ;typedef int ARR[10]; ARR *p1 = &a;
    p1, &a首行地址;首行地址转首元素地址:*p1;
    第i个元素的地址*p1 +i; 取第i个元素的内容:*(*p1+i);
    2)直接定义数组指针变量(常用)
    int a[10]; int (*p)[10]; p = &a;
    3)定义数组指针类型,再根据类型定义变量(常用)
    int a[10]; typedef int (*ARR)[10]; ARR p; p = &a;
    6.多维数组
    int a[3][4];
    1)多维数组名"a",代表第0个元素的地址(相当于整个多维数组首元素地址或首行元素地址)
    "a+1"跳四个元素(int[4]),16个字节。
    2)多维数组名取址"&a",代表整个数组的地址。
    "&a+1"跳整个数组大小(int [3][4]),48个字节 。
    sizeof(a) == 48; sizeof(a[0]) == 16; sizeof(a[0][0]) = 4;
    3)多维数组名就相当于数组指针;如上;( int (*p)[4] = a 或 int (*q)[4] = NULL, q = a);
    4)特殊情况,当(数组指针)与(多维数组的数组名的步长)不同时;
    ""

    5)"二级指针与二维数组不是同一种类型";


    C提高第五天=================================================================

    "定义结构体变量时,要把定义语句写在函数的定义区,如果写在其他地方,由于编译器的问题,会导致定义变量不成功,编译器不认识"。

    "结构体变量之间可以进行直接赋值,但是需要注意深拷贝和浅拷贝问题"(下面有讲解)
    1.结构体:
    Stu *s1 = NULL;
    Stu p = { 20, "nihao","sada" };
    s1 = &p; //这里的注意写法,给结构体指针变量整体赋值。(不能写成 *s1 = p ,原因 *s1是已经开始取结构体的内容,因为s1没有赋值,相当于野指针,不能取值);
    2.结构体的名是一个普通的变量(和 int a 中的 a 无区别);

    3.结构体中给指针的赋值操作和数组的赋值操作。(特别注意)
    ypedef struct Stu
    {
    int age;
    char name[20];
    char *p;
    char *size;
    }Stu;

    int main07(void)
    {
    Stu *s1 = NULL;
    Stu p = { 20, "nihao","sada" };
    s1 = &p; //这里的注意写法,给结构体指针变量整体赋值。(不能写成 *s1 = p ,原因 *s1是已经开始取结构体的内容,因为s1没有赋值,相当于野指针,不能取值);

    printf("%d, %s, %s ", s1->age, s1->name, s1->p);

    printf(" ");
    system("pause");
    return 0;
    }

  • 相关阅读:
    互联网协议入门(一)(转)
    程序员的自我修养——操作系统篇(转)
    程序员的自我修养(2)——计算机网络(转)
    里氏替换原则
    Windows Phone 自学笔记 : ApplicationBar
    如何写好代码
    C# 通过操作注册表控制系统 (更新)
    优秀PPT 设计的十大秘诀
    设计模式学习--面向对象的5条设计原则
    SOLID (面向对象设计) From 维基百科
  • 原文地址:https://www.cnblogs.com/yyx1-1/p/5679718.html
Copyright © 2020-2023  润新知