C语言入门(二)

1、多级指针

int main() {
    // 指针是用来记录内存地址的,但它本身也有内存地址。
    int i = 1000;
    int *ip = &i; // 取出i的内存地址ip。
    printf("i的值是%d,内存地址是%p\n", i, ip);

    int **ipp = &ip; // 取出内存地址ip的内存地址ipp。
    printf("i的内存地址的值是%p,内存地址的内存地址是%p\n", ip, ipp);
  
    int ***ippp = &ipp; // 取出内存地址ip的内存地址ipp的内存地址ippp。
    printf("i的内存地址的内存地址的值是%p,内存地址的内存地址的内存地址是%p\n", ipp, ippp);

    // int ****ippp = &ippp; // 报错,最多三级指针

    int ippp_value = *ippp;
    int ipp_value = **ippp;
    int ip_value = ***ippp;
    printf("ippp_value值是%p,ipp_value值是%p,ip_value值是%d\n", ippp_value, ipp_value, ip_value);
}

打印结果:

i的值是1000,内存地址是0x7ff7b0c9443c
i的内存地址的值是0x7ff7b0c9443c,内存地址的内存地址是0x7ff7b0c94430
i的内存地址的内存地址的值是0x7ff7b0c94430,内存地址的内存地址的内存地址是0x7ff7b0c94428
ippp_value值是0xb0c94430,ipp_value值是0xb0c9443c,ip_value值是1000

2、数组与数组指针

int main() {
    int intArray[] = {1, 2, 3, 4};
    for (int i = 0; i < sizeof(intArray) / sizeof(intArray[0]); ++i) {
        printf(" i=%d,内存地址是=%p\n", i, &intArray[i]); // 地址连续
    }

    // 数组本身就是它的内存地址,它内存地址又是它第一个元素的内存地址。
    printf("intArray=%p\n", intArray);
    printf("&intArray=%p\n", &intArray);
    printf("&intArray[0]=%p\n", &intArray[0]);
}

打印结果:

i=0,内存地址是=0x7ff7b3824420
i=1,内存地址是=0x7ff7b3824424
i=2,内存地址是=0x7ff7b3824428
i=3,内存地址是=0x7ff7b382442c
intArray=0x7ff7b3824420
&intArray=0x7ff7b3824420
&intArray[0]=0x7ff7b3824420

数组中的元素地址是连续的,每次挪动4个字节,因为是int数组。

int main() {
    int intArray[] = {1, 2, 3, 4};
  
    int *intArray_p = intArray;
    printf("从intArray_p地址中取值%d\n", *intArray_p); // 只能取到第一个元素的值
    
    // 那想获取到第二个元素的值呢,就要指针挪动
    printf("从intArray_p地址中取出第二个元素的值%d\n", *++intArray_p); // 取第二个元素的值
    
    // 如果想要取第四个元素。因为现在数组指针指向第二个元素,需要再往后移2位
    intArray_p += 2;
    printf("从intArray_p地址中取出第二个元素的值%d\n", *intArray_p); // 取第四个元素的值

    // 将指针重新回到1
    intArray_p -= 3;
    printf("将指针重新回到1,value=%d\n", *intArray_p);
}

3、采用指针遍历数组

int main() {
    int intArray[] = {1, 2, 3, 4};
    for (int i = 0; i < sizeof(intArray) / sizeof(intArray[0]); ++i) {
        printf("第%d元素的值是%d,内存地址是%p\n", i, *(intArray + i), intArray + i);
    }
}

打印结果:

第0元素的值是1,内存地址是0x7ff7b5415420
第1元素的值是2,内存地址是0x7ff7b5415424
第2元素的值是3,内存地址是0x7ff7b5415428
第3元素的值是4,内存地址是0x7ff7b541542c

根据内存地址,依次输出元素的值。可以看出内存地址是连续的。间隔4个字节,一个int值占四个字节

4、循环时给数组赋值

int main() {
    int intArray[4]; // 定义数组,长度4,未赋值。
    int *intArrayP = intArray; // 将数组转成指针。
    printf("intArray的内存地址是%p,默认元素的值是%d\n", intArrayP, *intArrayP);
    
    for (int i = 0; i < sizeof(intArray) / sizeof(intArray[0]); ++i) {
        // 第一个元素地址是intArrayP,那第二、三、四的地址,依次+1。
        // 第一个元素赋值1000,第二、三、四的值也依次+1。
        *(intArrayP + i) = 1000 + i;
        printf("第%d个元素的值是%d\n", i,*(intArrayP + i));
    }
}

打印结果:

intArray的内存地址是0x7ff7bda22420,默认元素的值是-1113447360
第0个元素的值是1000,地址是0x7ff7bda22420
第1个元素的值是1001,地址是0x7ff7bda22424
第2个元素的值是1002,地址是0x7ff7bda22428
第3个元素的值是1003,地址是0x7ff7bda2242c

地址连续,值依次增加1。

5、数组指针操作的几种方式

int main() {
    int intArray[] = {1, 3, 5, 7};
    int *intArrayP = &intArray;
    for (int i = 0; i < sizeof(intArray) / sizeof(intArray[0]); ++i) {
        printf("地址是:%p。第一种:值是%d,第二种:值是%d,第三种:值是%d\n", &intArray[i],intArrayP[i], intArray[i], *(intArrayP + i));
    }
}

打印结果:

地址是:0x7ff7b5240420。第一种:值是1,第二种:值是1,第三种:值是1
地址是:0x7ff7b5240424。第一种:值是3,第二种:值是3,第三种:值是3
地址是:0x7ff7b5240428。第一种:值是5,第二种:值是5,第三种:值是5
地址是:0x7ff7b524042c。第一种:值是7,第二种:值是7,第三种:值是7

第一种:根据指针获取值;

第二种:根据数组取值;

第三种:根据内存地址获取值;

6、指针类型有何用?

不同类型的指针偏移量是不一样的。char占1个字节,short占2个字节,int、float占4个字节,double、long、char *占8个字节

7、函数指针

// 监听回调的方法
void onClick(char* msg) {
    printf("%s\n", msg);
}

// 定义一个监听方法,具体实现在下面
void setOnclickListener(void (*clickCallback)(char*));

int mainT2_6() {
    // 第一种写法,直接将函数地址传入。函数本身就是地址。
    setOnclickListener(onClick);

    // 第二种写法:和写法三类似,但写法二更标准。
    // 先定义一个call函数,然后call函数的值修改成onClick()函数的值。再将call函数的地址作为参数传入。
    // 这样做的好处是,避免修改onClick()函数导致全局改变
    void (*call)(char*);
    call = onClick;
    setOnclickListener(call);

    // 第三种写法:第二种写法的非标注写法,在某些编译器上有可能报错。
    void (*call2)(char*) = onClick;
    setOnclickListener(call2);

    // 不写参数,这种简写好像也可以。
    void *call3 = onClick;
    setOnclickListener(call3);
}

void setOnclickListener(void (*clickCallback)(char*)) {
    // 某种情况下会进行回调
    clickCallback("我被点击啦...");
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容