• c++ 拾遗


    1. typedef的用法

    typedef的作用是真正意义上地定义一种别名,而不是一种简单的宏替换。

    typedef 与 #define的区别:

    案例一:

    通常讲,typedef要比#define要好,特别是在有指针的场合。请看例子:

    typedef char *pStr1;

    #define pStr2 char *;

    pStr1 s1, s2;

    pStr2 s3, s4;
    在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是我们所预期的指针变量,根本原因就在于#define只是简单的字符串替换而typedef则是为一

    个类型起新名字。

    注意语句char* pa,pb; 其中pa定义成了一个字符指针,而pb则是定义成了一个字符变量。这个问题我一直没有注意过,对于int来说,是一样的,比如int *a,b实际定义了一个指针和一个整型数。所以好的编程习惯应该是将*与变量名连接在一起,而不是紧跟在类型后。比如:char *pa, pb;这个就比较一目了然了。  

    再考虑这个问题:

    下面的代码中编译器会报一个错误,你知道是哪个语句错了吗?

    typedef char * pStr;

    char string[4] = "abc";

    const char *p1 = string;

    const pStr p2 = string;

    p1++;

    p2++;

    答案是:p2++会报错。

    const char *p1 = string 意思是说一个指向const char类型的指针。。
    p1指针是一个变量。他可以指向任意的char对象。就算不是const定义的char也可以,p1可以指向不同的char对象,因为他是一个变量。但他无论是指向const char对象还是char对象。都不能改变其指向对象的值。就是说上例子p1不能对string做修改。只能读取string的值。

    typedef char *pStr
    const pStr p2 = string 这里是typedef和指针共用时的坑爹指出。
    const pStr p2 = string
    pStr const p2 = string
    char* const p2 = string 上面3个语句是一个意思。
    就是说p2是一个指向非const、char类型的对象的const指针。p2初始化之后就不能够指向第二个对象。但p2可以对string的值进行修改。

    对于用typedef定义函数指针别名的格式,以前自己没有见过,有必要看看。

    typedef void(*SIG_TYPE)(int); 定义了一个函数指针SIG_TYPE,函数的返回类型是void,参数为int。

        2.   关于指针。 转载一篇别人的文章

    指针是C语言的精华,它是一柄“双刃剑”,用的好与坏就看使用者的功力了。下面就一道面试题,看一下指针与数组的区别。

    char *p1, *p2;
    char ch[12];
    char **pp;
    p1 = ch;
    pp = &ch;
    p2 = *pp;
    问p1和p2是否相同

        题目如上,找出其中的不妥之处。

        首先,数组ch是没有初始化的。其次,一个比较隐含的地方是,数组名可以代表数组第一个元素的首地址,这个没有问题,但是,数组名并非一个变量,数组分配 完成后,数组名就是固定的,地址也是固定的。这样导致的结果就是绝对不能把数组名当作变量来进行处理。上述题目中,pp=&ch,显然是把数组名 当作指针变量来使用了,这样肯定出问题。

        这个题目存在的两个问题,第一个问题比较简单,可以认为是粗心大意。但是第二个问题就是相当复杂了,扩展开来,那就是C语言中的精华中的指针和数组的联系 与区别问题了。

        下面分为两步,首先看一下指针和数组的区别方法,然后提出对上述程序的修改方案。

    1 指针和数组的区别

    (1)指针和数组的分配

        数组是开辟一块连续的内存空间,数组本身的标识符(也就是通常所说的数组名)代表整个数组,可以使用sizeof来获得数组所占据内存空间的大小(注意, 不是数组元素的个数,而是数组占据内存空间的大小,这是以字节为单位的)。举例如下:

    #include <stdio.h>
    int main(void)
    {
    char a[] = "hello";
    int b[] = {1, 2, 3, 4, 5};
    printf("a: %d\n", sizeof(a));
    printf("b memory size: %d bytes\n", sizeof(b));
    printf("b elements: %d\n", sizeof(b)/sizeof(int));
    return 0;
    }

        数组a为字符型,后面的字符串实际上占据6个字节空间(注意最后有一个\0标识字符串的结束)。从后面sizeof(b)就可以看出如何获得数组占据的内 存空间,如何获得数组的元素数目。至于int数据类型分配内存空间的多少,则是编译器相关的。gcc默认为int类型分配4个字节的内存空间。

    (2)空间的分配

        这里又分为两种情况。

        第一,如果是全局的和静态的
        char *p = “hello”;
        这是定义了一个指针,指向rodata section里面的“hello”,可以被编译器放到字符串池。在汇编里面的关键字为.ltorg。意思就是在字符串池里的字符串是可以共享的,这也是 编译器优化的一个措施。
        char a[] = “hello”;
        这是定义了一个数组,分配在可写数据块,不会被放到字符串池。

        第二,如果是局部的
        char *p = “hello”;
        这是定义了一个指针,指向rodata section里面的“hello”,可以被编译器放到字符串池。在汇编里面的关键字为.ltorg。意思就是在字符串池里的字符串是可以共享的,这也是 编译器优化的一个措施。另外,在函数中可以返回它的地址,也就是说,指针是局部变量,但是它指向的内容是全局的。
        char a[] = “hello”;
        这是定义了一个数组,分配在堆栈上,初始化由编译器进行。(短的时候直接用指令填充,长的时候就从全局字符串表拷贝),不会被放到字符串池(同样如前,可 能会从字符串池中拷贝过来)。注意不应该返回它的地址。

    (3)使用方法

        如果是全局指针,用于不需要修改内容,但是可能会修改指针的情况。
        如果是全局数组,用于不需要修改地址,但是却需要修改内容的情况。
        如果既需要修改指针,又需要修改内容,那么就定义一个数组,再定义一个指针指向它就可以了。

    2 我编写的修改方案

    [armlinux@lqm pointer]$ cat pointer.c
    /*
    * Copyright 2007 (c), Shandong University
    * All rights reserved.
    *
    * Filename : test.c
    * Description: about pointer
    * Author : Liu Qingmin
    * Version : 1.0
    * Date : 2007-08-27
    */
    #include <stdio.h>
    /*
    * define a macro which is used to debug array mode and pointer mode.
    * if 1, debug array mode; else debug pointer mode.
    * You can change it according to your decision.
    */
    #define ARRAY_OR_POINTER 0
    int main(void)
    {
    char *p1;
    char *p2;
    char **pp;
    //test1
    #if ARRAY_OR_POINTER
    char ch[] = "hello, world!\n";
    printf("%d, %d, %d, %d\n", sizeof(p1), sizeof(p2),
    sizeof(pp), sizeof(ch));
    #else
    char *ch = "hello, world!\n";
    printf("%d, %d, %d, %d\n", sizeof(p1), sizeof(p2),
    sizeof(pp), sizeof(ch));
    #endif
    //test2
            p1 = ch;
    #if ARRAY_OR_POINTER
                    pp = &p1;
    #else
                    pp = &ch;
    #endif
            p2 = *pp;
    if (p1 == p2) {
    printf("p1 equals to p2\n");
    } else {
    printf("p1 doesn't equal to p2\n");
    }
    return 0;
    }

        执行结果如下:

    // ARRAY_OR_POINTER为0时
    [armlinux@lqm pointer]$ ./test
    4, 4, 4, 4
    p1 equals to p2
    // ARRAY_OR_POINTER为1时
    [armlinux@lqm pointer]$ ./test
    4, 4, 4, 15
    p1 equals to p2

        如果使用了数组定义方式,而又使用pp=&ch,那么就会出现类似下面的错误:

    [armlinux@lqm pointer]$ make
    gcc -Wall -g -O2 -c -o pointer.o pointer.c
    pointer.c: In function `main':
    pointer.c:44: warning: assignment from incompatible pointer type
    gcc -Wall -g -O2 pointer.o -o test
    [armlinux@lqm pointer]$ ./test
    4, 4, 4, 15
    p1 doesn't equal to p2

    主要就是,数组定义时,数组名的类型应该是char (*)[12],这个与char**是有区别的。所以如果需要对数组名进行其他操作的话,最好先用一个指针承接。

        3.   struct的存储空间大小

    一般按照四位对齐,不及四位的话会补齐。

        4.   函数指针

    下面程序中关于函数指针的使用都是合法的。

    #include <iostream>
    using namespace std;
    float f(const float&);
    int main()
    {
    typedef float (*PFUN)(const float &);
    PFUN p1 = f;
    PFUN p2 = &f;
    cout<<p1(1)<<endl;
    cout<<(*p1)(1)<<endl;
    cout<<p2(1)<<endl;
    cout<<(*p2)(1)<<endl;
    }
    float f(const float& a)
    {
    return a+1;
    }
    程序的输出为:
    2
    2
    2
    2

     

    如何返回指向函数的指针呢?
    比如: int (*ff(int)) (int *,int );
    在这个,ff是一个函数,它有一个int类型的形参,返回一个指向函数的指针。指针指向的函数返回值为int类型,接受一个int*型和一个int型的形参。
    这个表达看上去比较复杂,可以使用typedef简化:
    typedef int (*PF)(int*,int);
    PF ff(int);
  • 相关阅读:
    C# NameValueCollection
    visual studio使用技巧创建自己代码片段
    C#在DataTable中使用LINQ
    [转]C# 中的.pdb/ .vshost.exe/ .vshost.exe.manifest文件讨论
    C#自定义控件在添加引用后不显示在工具箱的解决方法
    Java 工程师
    redis-CRC16
    sql server-当天日期减去一天 应该如何写
    清除访问Windows共享时缓存的凭据
    cmd下查看当前登陆用户
  • 原文地址:https://www.cnblogs.com/bovine/p/2282386.html
Copyright © 2020-2023  润新知