精华内容
下载资源
问答
  • C程序设计语言--缓冲、常见的问题 分类: C/C++ 《c程序设计语言》2013-10-03 18:24 69人阅读 评论(0) 收藏 举报 C程序设计语言c语言缓冲 C语言中你经常没意识到的问题 1、下面的程序...
     

    C程序设计语言--缓冲、常见的问题

    分类: C/C++ 《c程序设计语言》 69人阅读 评论(0) 收藏 举报

    C语言中你经常没意识到的问题

    1、下面的程序并不见得会输出 hello-std-out,你知道为什么吗?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <stdio.h>
    #include <unistd.h>
    int main() 
    {
        while(1)
        {
            fprintf(stdout,"hello-std-out");
            fprintf(stderr,"hello-std-err");
            sleep(1);
        }
        return 0;
    }

    参考答案:stdout和stderr是不是同设备描述符。stdout是块设备,stderr则不是。对于块设备,只有当下面几种情况下才会被输入,1)遇到回车,2)缓冲区满,3)flush被调用。而stderr则不会。

    2、下面的程序看起来是正常的,使用了一个逗号表达式来做初始化。可惜这段程序是有问题的。你知道为什么呢?

    1
    2
    3
    4
    5
    6
    7
    8
    #include <stdio.h>
     
    int main()
    {
        int a = 1,2;
        printf("a : %d\n",a);
        return 0;
    }

    参考答案:这个程序会得到编译出错(语法出错),逗号表达式是没错,可是在初始化和变量声明时,逗号并不是逗号表达式的意义。这点要区分,要修改上面这个程序,你需要加上括号: int a = (1,2);

    3、下面的程序会有什么样的输出呢?

    1
    2
    3
    4
    5
    6
    7
    #include <stdio.h>
    int main()
    {
        int i=43;
        printf("%d\n",printf("%d",printf("%d",i)));
        return 0;
    }

    参考答案:程序会输出4321,你知道为什么吗?要知道为什么,你需要知道printf的返回值是什么。printf返回值是输出的字符个数。

    4、下面的程序会输出什么?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <stdio.h>
    int main() 
    {
        float a = 12.5;
        printf("%d\n", a);
        printf("%d\n", (int)a);
        printf("%d\n", *(int *)&a);
        return 0; 
    }

    参考答案:
    该项程序输出如下所示,
    0
    12
    1095237632
    原因是:浮点数是4个字节,12.5f 转成二进制是:01000001010010000000000000000000,十六进制是:0×41480000,十进制是:1095237632。所以,第二和第三个输出相信大家也知道是为什么了。而对于第一个,为什么会输出0,我们需要了解一下float和double的内存布局,如下:

    • float: 1位符号位(s)、8位指数(e),23位尾数(m,共32位)
    • double: 1位符号位(s)、11位指数(e),52位尾数(m,共64位)

    然后,我们还需要了解一下printf由于类型不匹配,所以,会把float直接转成double,注意,12.5的float和double的内存二进制完全不一样。别忘了在x86芯片下使用是的反字节序,高位字节和低位字位要反过来。所以:

    • float版:0×41480000 (在内存中是:00 00 48 41)
    • double版:0×4029000000000000 (在内存中是:00 00 00 00 00 00 29 40)

    而我们的%d要求是一个4字节的int,对于double的内存布局,我们可以看到前四个字节是00,所以输出自然是0了。

    这个示例向我们说明printf并不是类型安全的,这就是为什么C++要引如cout的原因了。

    5、下面,我们再来看一个交叉编译的事情,下面的两个文件可以编译通过吗?如果可以通过,结果是什么?

    file1.c

    1
    int arr[80];

    file2.c

    1
    2
    3
    4
    5
    6
    7
    extern int *arr;
    int main() 
    {     
        arr[1] = 100;
        printf("%d\n", arr[1]);
        return 0; 
    }

    参考答案:该程序可以编译通过,但运行时会出错。为什么呢?原因是,在另一个文件中用 extern int *arr来外部声明一个数组并不能得到实际的期望值,因为他们的类型并不匹配。所以导致指针实际并没有指向那个数组。注意:一个指向数组的指针,并不等于一个数组。修改:extern int arr[]。(参考:ISO C语言 6.5.4.2 节)

    6、请说出下面的程序输出是多少?并解释为什么?(注意,该程序并不会输出 “b is 20″)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #include <stdio.h>
    int main() 
    {     
        int a=1;     
        switch(a)     
        {  
            int b=20;         
            case 1:
                printf("b is %d\n",b);
                break;
            default:
                printf("b is %d\n",b);
                break;
        }
        return 0;
    }

    参考答案:该程序在编译时,可能会出现一条warning: unreachable code at beginning of switch statement。我们以为进入switch后,变量b会被初始化,其实并不然,因为switch-case语句会把变量b的初始化直接就跳过了。所以,程序会输出一个随机的内存值。

    7、请问下面的程序会有什么潜在的危险?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <stdio.h>
    int main() 
    {     
        char str[80];
        printf("Enter the string:");
        scanf("%s",str);
        printf("You entered:%s\n",str);
        return 0;
    }

    参考答案:本题很简单了。这个程序的潜在问题是,如果用户输入了超过80个长度的字符,那么就会有数组越界的问题了,你的程序很有可以及会crash了。

    8、请问下面的程序输出什么?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <stdio.h>
    int main() 
    {
        int i;
        i = 10;
        printf("i : %d\n",i);
        printf("sizeof(i++) is: %d\n",sizeof(i++));
        printf("i : %d\n",i);
        return 0;
    }

    参考答案:如果你觉得输出分别是,10,4,11,那么你就错了,错在了第三个,第一个是10没有什么问题,第二个是4,也没有什么问题,因为是32位机上一个int有4个字节。但是第三个为什么输出的不是11呢?居然还是10?原因是,sizeof不是一个函数,是一个操作符,其求i++的类型的size,这是一件可以在程序运行前(编译时)完全的事情,所以,sizeof(i++)直接就被4给取代了,在运行时也就不会有了i++这个表达式。

    9、请问下面的程序的输出值是什么?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #include <stdio.h>
    #include <stdlib.h>
     
    #define SIZEOF(arr) (sizeof(arr)/sizeof(arr[0]))
    #define PrintInt(expr) printf("%s:%d\n",#expr,(expr))
     
    int main()
    {
        /* The powers of 10 */
        int pot[] = {
                        0001,
                        0010,
                        0100,
                        1000
                    };
     
        int i;
        for(i=0;i<SIZEOF(pot);i++)
            PrintInt(pot[i]);
             
        return 0;
    }

    参考答案:好吧,如果你对于PrintInt这个宏有问题的话,你可以去看一看《语言的歧义》中的第四个示例。不过,本例的问题不在这里,本例的输出会是:1,8,64,1000,其实很简单了,以C/C++中,以0开头的数字都是八进制的。

    10、请问下面的程序输出是什么?(绝对不是10)

    #include 
    #define PrintInt(expr) printf("%s : %dn",#expr,(expr))
    
    int main()  
    {
        int y = 100;
        int *p;
        p = malloc(sizeof(int));
        *p = 10;
        y = y/*p; /*dividing y by *p */;
        PrintInt(y);
        return 0;
    }
    

    参考答案:本题输出的是100。为什么呢?问题就出在 y = y/*p;上了,我们本来想的是 y / (*p) ,然而,我们没有加入空格和括号,结果y/*p中的 /*被解释成了注释的开始。于是,这也是整个恶梦的开始。

    11、下面的输出是什么?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <stdio.h>
    int main() 
    {
        int i = 6;
        if( ((++i < 7) && ( i++/6)) || (++i <= 9))
            ;
     
        printf("%d\n",i);
        return 0;
    }

    参考答案:本题并不简单的是考前缀++或反缀++,本题主要考的是&&和||的短路求值的问题。所为短路求值:对于(条件1 && 条件2),如果“条件1”是false,那“条件2”的表达式会被忽略了。对于(条件1 || 条件2),如果“条件1”为true,而“条件2”的表达式则被忽略了。所以,我相信你会知道本题的答案是什么了。

    12、下面的C程序是合法的吗?如果是,那么输出是什么?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <stdio.h>
    int main() 
    {
        int a=3, b = 5;
     
        printf(&a["Ya!Hello! how is this? %s\n"], &b["junk/super"]);
         
        printf(&a["WHAT%c%c%c  %c%c  %c !\n"], 1["this"],
            2["beauty"],0["tool"],0["is"],3["sensitive"],4["CCCCCC"]);
             
        return 0; 
    }

    参考答案:
    本例是合法的,输出如下:

    Hello! how is this? super
    That is C !

    本例主要展示了一种另类的用法。下面的两种用法是相同的:

    “hello”[2]
    2["hello"]

    如果你知道:a[i] 其实就是 *(a+i)也就是 *(i+a),所以如果写成 i[a] 应该也不难理解了。

    13、请问下面的程序输出什么?(假设:输入 Hello, World)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <stdio.h>
    int main() 
    {
        char dummy[80];
        printf("Enter a string:\n");
        scanf("%[^r]",dummy);
        printf("%s\n",dummy);
        return 0;
    }

    参考答案:本例的输出是“Hello, Wo”,scanf中的”%[^r]“是从中作梗的东西。意思是遇到字符r就结束了。

    14、下面的程序试图使用“位操作”来完成“乘5”的操作,不过这个程序中有个BUG,你知道是什么吗?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #include <stdio.h>
    #define PrintInt(expr) printf("%s : %d\n",#expr,(expr))
    int FiveTimes(int a) 
    {
        int t;
        t = a<<2 + a;
        return t;
    }
     
    int main() 
    {
        int a = 1, b = 2,c = 3;
        PrintInt(FiveTimes(a));
        PrintInt(FiveTimes(b));
        PrintInt(FiveTimes(c));
        return 0;
    }

    参考答案:本题的问题在于函数FiveTimes中的表达式“t = a<<2 + a;”,对于a<<2这个位操作,优先级要比加法要低,所以这个表达式就成了“t = a << (2+a)”,于是我们就得不到我们想要的值。该程序修正如下:

    1
    2
    3
    4
    5
    6
    int FiveTimes(int a) 
    {
        int t;
        t = (a<<2) + a;
        return t;
    }

    C程序设计语言--全局变量的认识

    分类: C/C++ 《c程序设计语言》 69人阅读 评论(0) 收藏 举报

    目录(?)[+]

    全局变量是C语言语法和语义中一个很重要的知识点,首先它的存在意义需要从三个不同角度去理解:对于程序员来说,它是一个记录内容的变量(variable);对于编译/链接器来说,它是一个需要解析的符号(symbol);对于计算机来说,它可能是具有地址的一块内存(memory)。其次是语法/语义:从作用域上看,带static关键字的全局变量范围只能限定在文件里,否则会外联到整个模块和项目中;从生存期来看,它是静态的,贯穿整个程序或模块运行期间(注意,正是跨单元访问和持续生存周期这两个特点使得全局变量往往成为一段受攻击代码的突破口,了解这一点十分重要);从空间分配上看,定义且初始化的全局变量在编译时在数据段(.data)分配空间,定义但未初始化的全局变量暂存(tentative definition)在.bss段,编译时自动清零,而仅仅是声明的全局变量只能算个符号,寄存在编译器的符号表内,不会分配空间,直到链接或者运行时再重定向到相应的地址上。

    我们将向您展现一下,非static限定全局变量在编译/链接以及程序运行时会发生哪些有趣的事情,顺便可以对C编译器/链接器的解析原理管中窥豹。以下示例对ANSI C和GNU C标准都有效,笔者的编译环境是Ubuntu下的GCC-4.4.3。

    第一个例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    /* t.h */
    #ifndef _H_
    #define _H_
    inta;
    #endif
     
    /* foo.c */
    #include <stdio.h>
    #include "t.h"
     
    struct{
       chara;
       intb;
    } b = { 2, 4 };
     
    intmain();
     
    voidfoo()
    {
        printf("foo:\t(&a)=0x%08x\n\t(&b)=0x%08x\n
            \tsizeof(b)=%d\n\tb.a=%d\n\tb.b=%d\n\tmain:0x%08x\n",
            &a, &b,sizeof b, b.a, b.b, main);
    }
     
    /* main.c */
    #include <stdio.h>
    #include "t.h"
     
    intb;
    intc;
     
    intmain()
    {
        foo();
        printf("main:\t(&a)=0x%08x\n\t(&b)=0x%08x\n
            \t(&c)=0x%08x\n\tsize(b)=%d\n\tb=%d\n\tc=%d\n",
            &a, &b, &c,sizeof b, b, c);
        return0;
    }

    Makefile如下:

    1
    2
    3
    4
    5
    6
    7
    8
    test: main.o foo.o
        gcc -otest main.o foo.o
     
    main.o: main.c
    foo.o: foo.c
     
    clean:
        rm*.o test

    运行情况:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    foo:    (&a)=0x0804a024
        (&b)=0x0804a014
        sizeof(b)=8
        b.a=2
        b.b=4
        main:0x080483e4
    main:   (&a)=0x0804a024
        (&b)=0x0804a014
        (&c)=0x0804a028
        size(b)=4
        b=2
        c=0

    这个项目里我们定义了四个全局变量,t.h头文件定义了一个整型a,main.c里定义了两个整型b和c并且未初始化,foo.c里定义了一个初始化了的结构体,还定义了一个main的函数指针变量。由于C语言每个源文件单独编译,所以t.h分别包含了两次,所以int a就被定义了两次。两个源文件里变量b和函数指针变量main被重复定义了,实际上可以看做代码段的地址。但编译器并未报错,只给出一条警告:

    1
    /usr/bin/ld: Warning: size of symbol'b' changed from 4in main.o to 8 in foo.o

    运行程序发现,main.c打印中b大小是4个字节,而foo.c是8个字节,因为sizeof关键字是编译时决议,而源文件中对b类型定义不一样。但令人惊奇的是无论是在main.c还是foo.c中,a和b都是相同的地址,也就是说,a和b被定义了两次,b还是不同类型,但内存映像中只有一份拷贝。我们还看到,main.c中b的值居然就是foo.c中结构体第一个成员变量b.a的值,这证实了前面的推断——即便存在多次定义,内存中只有一份初始化的拷贝。另外在这里c是置身事外的一个独立变量。

    为何会这样呢?这涉及到C编译器对多重定义的全局符号的解析和链接。在编译阶段,编译器将全局符号信息隐含地编码在可重定位目标文件的符号表里。这里有个“强符号(strong)”和“弱符号(weak)”的概念——前者指的是定义并且初始化了的变量,比如foo.c里的结构体b,后者指的是未定义或者定义但未初始化的变量,比如main.c里的整型b和c,还有两个源文件都包含头文件里的a。当符号被多重定义时,GNU链接器(ld)使用以下规则决议:

    • 不允许出现多个相同强符号。
    • 如果有一个强符号和多个弱符号,则选择强符号。
    • 如果有多个弱符号,那么先决议到size最大的那个,如果同样大小,则按照链接顺序选择第一个。

    像上面这个例子中,全局变量a和b存在重复定义。如果我们将main.c中的b初始化赋值,那么就存在两个强符号而违反了规则一,编译器报错。如果满足规则二,则仅仅提出警告,实际运行时决议的是foo.c中的强符号。而变量a都是弱符号,所以只选择一个(按照目标文件链接时的顺序)。

    事实上,这种规则是C语言里的一个大坑,编译器对这种全局变量多重定义的“纵容”很可能会无端修改某个变量,导致程序不确定行为。如果你还没有意识到事态严重性,我再举个例子。

    第二个例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    /* foo.c */
    #include <stdio.h>;
     
    struct{
        inta;
        intb;
    } b = { 2, 4 };
     
    intmain();
     
    voidfoo()
    {
        printf("foo:\t(&b)=0x%08x\n\tsizeof(b)=%d\n
            \tb.a=%d\n\tb.b=%d\n\tmain:0x%08x\n",
            &b,sizeof b, b.a, b.b, main);
    }
     
    /* main.c */
    #include <stdio.h>
     
    intb;
    intc;
     
    intmain()
    {
        if(0 == fork()) {
            sleep(1);
            b = 1;
            printf("child:\tsleep(1)\n\t(&b):0x%08x\n
                \t(&c)=0x%08x\n\tsizeof(b)=%d\n\tset b=%d\n\tc=%d\n",
                &b, &c,sizeof b, b, c);
            foo();
        }else {
            foo();
            printf("parent:\t(&b)=0x%08x\n\t(&c)=0x%08x\n
                \tsizeof(b)=%d\n\tb=%d\n\tc=%d\n\twait child...\n",
                &b, &c,sizeof b, b, c);
            wait(-1);
            printf("parent:\tchild over\n\t(&b)=0x%08x\n
                \t(&c)=0x%08x\n\tsizeof(b)=%d\n\tb=%d\n\tc=%d\n",
                &b, &c,sizeof b, b, c);
        }
        return0;
    }

    运行情况如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    foo:    (&b)=0x0804a020
        sizeof(b)=8
        b.a=2
        b.b=4
        main:0x080484c8
    parent: (&b)=0x0804a020
        (&c)=0x0804a034
        sizeof(b)=4
        b=2
        c=0
        wait child...
    child: sleep(1)
        (&b):0x0804a020
        (&c)=0x0804a034
        sizeof(b)=4
        setb=1
        c=0
    foo:    (&b)=0x0804a020
        sizeof(b)=8
        b.a=1
        b.b=4
        main:0x080484c8
    parent: child over
        (&b)=0x0804a020
        (&c)=0x0804a034
        sizeof(b)=4
        b=2
        c=0

    (说明一点,运行情况是直接输出到stdout的打印,笔者曾经将./test输出重定向到log中,结果发现打印的执行序列不一致,所以采用默认输出。)

    这是一个多进程环境,首先我们看到无论父进程还是子进程,main.c还是foo.c,全局变量b和c的地址仍然是一致的(当然只是个逻辑地址),而且对b的大小不同模块仍然有不同的决议。这里值得注意的是,我们在子进程中对变量b进行赋值动作,从此子进程本身包括foo()调用中,整型b以及结构体成员b.a的值都是1,而父进程中整型b和结构体成员b.a的值仍是2,但它们显示的逻辑地址仍是一致的。

    个人认为可以这样解释,fork创建新进程时,子进程获得了父进程上下文“镜像”(自然包括全局变量),虚拟地址相同但属于不同的进程空间,而且此时真正映射的物理地址中只有一份拷贝,所以b的值是相同的(都是2)。随后子进程对b改写,触发了操作系统的写时拷贝(copy on write)机制,这时物理内存中才产生真正的两份拷贝,分别映射到不同进程空间的虚拟地址上,但虚拟地址的值本身仍然不变,这对于应用程序来说是透明的,具有隐瞒性。

    还有一点值得注意,这个示例编译时没有出现第一个示例的警告,即对变量b的sizeof决议,笔者也不知道为什么,或许是GCC的一个bug?

    第三个例子

    这个例子代码同上一个一致,只不过我们将foo.c做成一个静态链接库libfoo.a进行链接,这里只给出Makefile的改动。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    test: main.o foo.o
        ar rcs libfoo.a foo.o
        gcc -static -otest main.o libfoo.a
     
    main.o: main.c
    foo.o: foo.c
     
    clean:
        rm-f *.o test

    运行情况如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    foo:    (&b)=0x080ca008
        sizeof(b)=8
        b.a=2
        b.b=4
        main:0x08048250
    parent: (&b)=0x080ca008
        (&c)=0x080cc084
        sizeof(b)=4
        b=2
        c=0
        wait child...
    child: sleep(1)
        (&b):0x080ca008
        (&c)=0x080cc084
        sizeof(b)=4
        setb=1
        c=0
    foo:    (&b)=0x080ca008
        sizeof(b)=8
        b.a=1
        b.b=4
        main:0x08048250
    parent: child over
        (&b)=0x080ca008
        (&c)=0x080cc084
        sizeof(b)=4
        b=2
        c=0

    从这个例子看不出有啥差别,只不过使用静态链接后,全局变量加载的地址有所改变,b和c的地址之间似乎相隔更远了些。不过这次编译器倒是给出了变量b的sizeof决议警告。

    到此为止,有些人可能会对上面的例子嗤之以鼻,觉得这不过是列举了C语言的某些特性而已,算不上黑。有些人认为既然如此,对于一切全局变量要么用static限死,要么定义同时初始化,杜绝弱符号,以便在编译时报错检测出来。只要小心地使用,C语言还是很完美的嘛~对于抱这样想法的人,我只想说,请你在夜深人静的时候竖起耳朵仔细聆听,你很可能听到Dennis Richie在九泉之下邪恶的笑声——不,与其说是嘲笑,不如说是诅咒……

    第四个例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    /* foo.c */
    #include <stdio.h>
     
    conststruct {
        inta;
        intb;
    } b = { 3, 3 };
     
    intmain();
     
    voidfoo()
    {
        b.a = 4;
        b.b = 4;
        printf("foo:\t(&b)=0x%08x\n\tsizeof(b)=%d\n
            \tb.a=%d\n\tb.b=%d\n\tmain:0x%08x\n",
            &b,sizeof b, b.a, b.b, main);
    }
     
    /* t1.c */
    #include <stdio.h>
     
    intb = 1;
    intc = 1;
     
    intmain()
    {
        intcount = 5;
        while(count-- > 0) {
            t2();
            foo();
            printf("t1:\t(&b)=0x%08x\n\t(&c)=0x%08x\n
                \tsizeof(b)=%d\n\tb=%d\n\tc=%d\n",
                &b, &c,sizeof b, b, c);
            sleep(1);
        }
        return0;
    }
     
    /* t2.c */
    #include <stdio.h>
     
    intb;
    intc;
     
    intt2()
    {
        printf("t2:\t(&b)=0x%08x\n\t(&c)=0x%08x\n
            \tsizeof(b)=%d\n\tb=%d\n\tc=%d\n",
            &b, &c,sizeof b, b, c);
        return0;
    }

    Makefile脚本:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    exportLD_LIBRARY_PATH:=.
     
    all:test
        ./test
     
    test: t1.o t2.o
        gcc -shared -fPIC -o libfoo.so foo.c
        gcc -otest t1.o t2.o -L. -lfoo
     
    t1.o: t1.c
    t2.o: t2.c
     
    .PHONY:clean
    clean:
        rm-f *.o *.so test*

    执行结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    ./test
    t2: (&b)=0x0804a01c
        (&c)=0x0804a020
        sizeof(b)=4
        b=1
        c=1
    foo:    (&b)=0x0804a01c
        sizeof(b)=8
        b.a=4
        b.b=4
        main:0x08048564
    t1: (&b)=0x0804a01c
        (&c)=0x0804a020
        sizeof(b)=4
        b=4
        c=4
    t2: (&b)=0x0804a01c
        (&c)=0x0804a020
        sizeof(b)=4
        b=4
        c=4
    foo:    (&b)=0x0804a01c
        sizeof(b)=8
        b.a=4
        b.b=4
        main:0x08048564
    t1: (&b)=0x0804a01c
        (&c)=0x0804a020
        sizeof(b)=4
        b=4
        c=4
        ...

    其实前面几个例子只是开胃小菜而已,真正的大坑终于出现了!而且这次编译器既没报错也没警告,但我们确实眼睁睁地看到作为main()中强符号的b被改写了,而且一旁的c也“躺枪”了。眼尖的读者发现,这次foo.c是作为动态链接库运行时加载的,当t1第一次调用t2时,libfoo.so还未加载,一旦调用了foo函数,b立马中弹,而且c的地址居然还相邻着b,这使得c一同中弹了。不过笔者有些无法解释这种行为的原因,有种说法是强符号的全局变量在数据段中是连续分布的(相应地弱符号暂存在.bss段或者符号表里),或许可以上报GNU的编译器开发小组。

    另外笔者尝试过将t1.c中的b和c定义前面加上const限定词,编译器仍然默认通过,但程序在main()中第一次调用foo()时触发了Segment fault异常导致奔溃,在foo.c里使用指针改写它也一样。推断这是GCC对const常量所在地址启用了类似操作系统写保护机制,但我无法确定早期版本的GCC是否会让这个const常量被改写而程序不会奔溃。

    至于volatile关键词之于全局变量,自测似乎没有影响。

    怎么样?看了最后一个例子是否有点“不明觉厉”呢?C语言在你心目中是否还是当初那个“纯洁”、“干净”、“行为一致”的姑娘呢?也许趁着你不注意的时候她会偷偷给你戴顶绿帽,这一切都是通过全局变量,特别在动态链接的环境下,就算全部定义成强符号仍然无法为编译器所察觉。而一些IT界“恐怖分子”也经常将恶意代码包装成全局变量注入到root权限下存在漏洞的操作序列中,就像著名的栈溢出攻击那样。某一天当你傻傻地看着一个程序出现未定义的行为却无法定位原因的时候,请不要忘记Richie大爷那来自九泉之下最深沉的“问候”~

    或许有些人会偷换概念,把这一切归咎于编译器和链接器身上,认为这同语言无关,但我要提醒你,正是编译/链接器的行为支撑了整个语言的语法和语义。你可以反过来思考一下为何C的胞弟C++推出“命名空间(namespace)”的概念,或者你可以使用其它高级语言,对于重定义的全局变量是否能通过编译这一关。

    所以请时刻谨记,C是一门很恐怖的语言!

    P.S.题外话写在最后。我无意挑起语言之争,只是就事论事地去“黑(hack)”一门语言而已,而且要黑就要黑得有理有力有层次,还要带点娱乐精神。其实黑一门语言并非什么尖端复杂的技术,个人觉得起码要做到两点:

    • 亲自动手写测试程序。动手写测试程序是开发人员必备的基础技能,只有现成的代码才能让人心服口服,那些只会停留在口头上的争论只能算作cheap hack。
    • 测试程序不能依赖于不成熟的代码。软件开发99%以上的bug都是基于不合格(substandard)开发人员导致,这并不能怪罪于语言以及编译器本身。使用诸如#define TRUE FALSE或者#define NULL 1之类的trick来黑C语言只能证明此人很有娱乐精神而不是真正的”hack value”,拿老北京梨园行当里的一句话——“那是下三滥的玩意儿”。

    展开全文
  • windows 用户变量和系统变量的区别

    千次阅读 2018-12-17 14:50:05
    点击“我的电脑→属性→高级系统设置”标签的“环境变量”...的时候我们会看到在用户变量和系统变量中都存在某一个环境变量,比如path,那么path的值到底是用户变量中的值还是系统变量中的值,或者两者都不是呢?...

    点击“我的电脑→属性→高级系统设置”标签的“环境变量”按钮,出现“环境变量”对话框,如果当前是以Administrator登录系统的用户,对话框的上面为Administrator的用户变量,对话框的下面为系统变量(即相当于系统中所有用户的用户变量)。有的时候我们会看到在用户变量和系统变量中都存在某一个环境变量,比如path,那么path的值到底是用户变量中的值还是系统变量中的值,或者两者都不是呢?答案是两者都不是。path变量的值是用户变量中的值与系统变量中的值的叠加。

    系统环境变量,对所有用户起作用,而用户环境变量只对当前用户起作用。 

                   例如你要用java,那么你把java的bin目录加入到path变量下面(添加方法),那么它就是系统环境变量,所有用户登陆,在命令行输入java都会有java的帮助信息出来。而如果你在某个用户的变量下面新建一个变量,那么它就只对这个用户有用,当你以其他用户登陆时这个变量就和不存在一样。

    系统变量:与windows操作系统包括网络状况有关,由操作系统定义。Administrators组的用户可以添加添加、修改或删除。
    用户变量:由操作系统、某些应用程序以及用户建立,例如WindowsXP安装程序将临时文件夹设定了默认存储位置,并视为用户变量。任何用户都可以添加、修改或删除。
     

    这些变量由 Windows XP 安装程序、某些应用程序以及用户建立。这些更改将写入注册表,而且通常立即生效。不过,在更改用户环境变量之后,应该重新启动所有打开的软件程序以使其读取新的注册表值。

    添加、改变变量的常见原因是为您希望在程序(脚本)中使用的变量提供所需的数据。


    环境变量的含义和值的示例:

    ******系统变量及说明    
    ******示例或注释
    ____________________    
    ____________________
    %ALLUSERSPROFILE% : 所有用户Profile文件位置。    
    ALLUSERSPROFILE=C:\Documents and Settings\All Users
    %APPDATA% : 应用程序数据的默认存放位置。    
    APPDATA=C:\Documents and Settings\Administrator\Application Data
    %CD% : 当前目录。    

    %CLIENTNAME% : 联接到终端服务会话时客户端的NETBIOS名。    
    CLIENTNAME=Console
    %ClusterLog%:集群日志路径    
    ClusterLog=C:\WINDOWS\Cluster\cluster.log
    %CMDCMDLINE% : 启动当前命令解释器程序路径及文件名。    
    %CMDCMDLINE% =C:\WINDOWS\system32\cmd.exe
    %CMDEXTVERSION% : 当前命令处理程序扩展版本号。    
    ClusterLog=C:\WINDOWS\Cluster\cluster.log
    %CommonProgramFiles% : 应用程序公用文件的路径    
    CommonProgramFiles=C:\Program Files\Common Files
    %COMPUTERNAME% : 计算机名。    
    COMPUTERNAME=XSJ004
    %COMSPEC% : 可执行命令外壳(命令处理程序,命令解释器)的路径。    
    ComSpec=C:\WINDOWS\system32\cmd.exe
    %DATE% : 当前日期(与DATE/t 命令同格式)    

    %ERRORLEVEL% : 最近使用的命令的错误代码。    

    %FP_NO_HOST_CHECK%:    
    FP_NO_HOST_CHECK=NO
    ____________________    
    ____________________
    %HOMEDRIVE% : 用户主目录(本地工作站)所在的驱动器盘符。    
    HOMEDRIVE=C:
    %HOMEPATH% : 用户主目录的完整路径。    
    HOMEPATH=\Documents and Settings\Administrator
    %HOMESHARE% : 用户共享主目录的网络路径。    

    ***用户主目录是在“本地用户和组”中指定的    

    ____________________    
    ____________________
    %LOGONSEVER% : 有效的当前登录会话的域名控制器名(登录的服务器)。    
    LOGONSERVER=\\OWEN
    %NUMBER_OF_PROCESSORS% : 计算机安装的处理器数。    
    NUMBER_OF_PROCESSORS=1
    %OS% : 操作系统的名字。(Windows XP 和 Windows 2000 列为 Windows_NT.)    
    OS=Windows_NT
    %Path% : 可执行文件的搜索路径。    
    Path=C:\WINDOWS\system32;C:\Program Files\Common Files\Adobe\AGL
    %PATHEXT% : 操作系统认为可被执行的文件扩展名。    
    PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH
    %PROCESSOR_ARCHITECTURE% : 处理器的芯片架构(体系结构)。    
    PROCESSOR_ARCHITECTURE=x86
    %PROCESSOR_IDENTFIER% : 处理器的描述(标识)。    
    PROCESSOR_IDENTIFIER=x86 Family 6 Model 8 Stepping 3, GenuineIntel
    %PROCESSOR_LEVEL% : 计算机的处理器的型号。    
    PROCESSOR_LEVEL=6
    %PROCESSOR_REVISION% : 处理器的修订号。    
    PROCESSOR_REVISION=0803
    %ProgramFiles% : Program Files应用程序安装的默认文件夹的路径。    
    ProgramFiles=C:\Program Files
    %PROMPT% : 当前命令解释器的命令提示设置。    
    PROMPT=$P$G
    %RANDOM% : 界于0 和 32767之间的随机十进制数。    

    %SESSIONNAME% : 连接到终端服务会话时的连接和会话名。    
    SESSIONNAME=Console
    %SYSTEMDRIVE% : Windows系统目录所在驱动器(盘符)。    
    SystemDrive=C:
    %SYSTEMROOT% : Windows系统目录。    
    SystemRoot=C:\WINDOWS
    %TEMP% :当前登录的用户可用应用程序的默认临时目录,有些程序会自动删去其临时文件。    
    TEMP=C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp
    %TMP% : 当前登录的用户可用应用程序的默认临时目录,有些程序会自动删去其临时文件。    
    TMP=C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp
    ***有些程序可能调用%TEMP%,有些则是%TMP%。两者的值默认是相同的。可以更改,建议不必要改动。    

    %TIME% : 当前时间(与TIME /t 命令同格式)。    

    %USERDNSDOMAIN%:当前用户所在的域的DNS表示    
    %USERDNSDOMAIN%=MCSE.COM
    %USERDOMAIN% : 包含用户帐号的域的名字。    
    USERDOMAIN=OWEN
    %USERNAME% : 当前登录的用户名    
    USERNAME=Administrator
    %USERPROFILE% : 当前用户配置文件(Profile文件)位置。    
    USERPROFILE=C:\Documents and Settings\Administrator
    %WINDIR% : 操作系统目录    
    windir=C:\WINDOWS
    --------------------- 
    作者:阳光的颜色 
    来源:CSDN 
    原文:https://blog.csdn.net/sxhlovehmm/article/details/44274633 
    版权声明:本文为博主原创文章,转载请附上博文链接!

    展开全文
  • 变量命名规范

    万次阅读 2015-10-25 21:52:40
    变量命名规范本节内容主要参考自代码大全(第二版)1、变量命名的注意事项 变量命名最关键的一点就是:名字...常见的限定词:Total, Sum, Average, Max, Min, Record, String, Pointer Num比较特殊,加在前面表示总数,加

    变量命名规范


    本节内容主要参考自代码大全(第二版)

    1、变量命名的注意事项

    • 变量命名最关键的一点就是:名字要能准确的描述出该变量所代表的事物
    • 变量名长度最好控制在10~16个字符之间
    • 对位于全局命名空间中的名字加以限定词,并且应该一般加在后面
      • 常见的限定词:Total, Sum, Average, Max, Min, Record, String, Pointer
      • Num比较特殊,加在前面表示总数,加在后面表示下标。不过为了避免混淆,总数最好用Total/Count来表示,下标用Index来表示
    • 准确使用对称词,如first/last

    举一些例子:

    变量用途 变量名称 备注
    支票累计额 checkTotal
    列车速度 velocity
    每页行数 linesPerPage
    员工序号 customerIndex 优于customerNum
    员工总数 customerTotal 优于numCustomers(复数)

    2、特定类型的数据命名

    2.1循环下标命名

    • 循环内常用 i, j, k做下标,且仅用于此处
    • 如果一个变量要在循环之外使用,要以具体的意义去命名,比如统计读取记录的数量,应当使用recordCount
    • 嵌套循环最好以实际意义来命名下标,如扫描矩阵用row, column

    2.2状态变量命名

    • 不要使用flag,应当明确指出具体状态,如用dataReady表示数据已经准备好了
    • 当一个状态变量表示多个状态时,有时需要进行操作,有时候也需要进行比较,结合枚举类型或者预定义常量来使用,如characterType & PRINTABLE_CHAR

    2.3临时变量命名

    • 尽量使用的“临时变量”的具体意义命名,而不是使用temp,要清楚该变量所代表数据的实际用途

    2.4布尔变量命名

    • 记住典型的布尔变量名
      • done,某事已完成
      • error,错误有发生
      • found,某值已找到
      • success/ok,某项操作成功,最好能更具体的表示是什么操作
    • 布尔变量的名称应当只有truefalse的含义,如sex就比male差很多
    • 使用肯定意义的布尔变量名,如notFound就比found差很多

    2.5枚举类型命名

    • 使用前缀,其一般为枚举类型名称
    enum Color
    {
        Color_Red,
        Color_Green,
        Color_Blue
    }

    2.6常量命名

    • 全部大写+下划线
    • 使用常量的意义命名,而不是数值
    • 推荐使用const定义常量,而不是#define

    3、非正式命名规则

    • 此处列出C++和Java命名规则的部分示例,这些都是笔者用起来非常舒服规则
    实体 描述
    localVariable 局部变量,首字母小写,其余单词首字母大写
    g_globalVariable 全局变量,使用g_前缀
    funtion_name 函数/方法,全部小写,单词之间用下划线隔开
    TypeName 类型定义,Camel写法,包括枚举和typedef,枚举总是复数形式
    Base_Enum 枚举类型元素,加上单数枚举类型前缀,Color_Red
    ClassName 类名,Camel写法,每个单词首字母大写,其余字母小写
    m_classVariable 类成员变量,使用前缀m_
    CONSTANT 常量,全部大写 + 下划线
    MACRO 常量,全部大写 + 下划线

    4、缩写规则

    • 有标准缩写的要使用标准缩写,如degree缩写为degdeletedel
    • 去掉非前置元音
    • 去掉虚词
    • 统一的在第n个字母后阶段,如xPoxyPos中的Pos表示都是Position

    5、应该避免的名字

    • 不要使用中文拼音甚至是拼音缩写
    • 避免使用令人误解的名字或者缩写
    • 避免使用具有相似含义的名字,如fileNumfileIndex
    • 避免使用拼写相似的名字
    • 避免在名字中使用数字,一般都可以转化为数组或者容器
    • 避免使用大小写区分变量
    • 避免使用易混淆的字符,如字母O/o和数字0,字母l和数字1,字母I和数字1

    总结

    • 变量命名最重要是就是要能体现其具体的意义
    • 变量名要方便阅读,不能太长也不能太短
    • 要形成自己的编码风格,一眼看过去就知道该名字代表是什么数据类型
    • 作为中国人,最经常犯的错误就是使用拼音及其缩写命名。笔者曾见过有人用MBPos表示面板位置,用T6表示机械臂第6个关节的坐标矩阵,看起来非常的吃力,包括他自己都经常忘记这些变量的具体含义
    展开全文
  • 剖解临时变量

    2011-12-22 14:34:56
    如果某个临时变量被赋值超过一次,并且它既不是循环变量,也不是集用临时变量。 。「循环变量」和「集用临时变量」就是两个典型例子: 循环变量(loop variables )[Beck]会随循环的每次运行而改变〔例如for...

    如果某个临时变量被赋值超过一次,并且它既不是循环变量,也不是集用临时变量。


    。「循环变量」和「集用临时变量」就是两个典型例子:

    循环变量(loop variables )[Beck]会随循环的每次运行而改变〔例如for (int i=0; i<10; i++)语句中的i〕;

    集用临时变量(collecting temporary variable)[Beck]负责将「通过整个函数的运算」而构成的某个值收集起来。

    除了这两种情况,还有很多临时变量用于保存一段冗长代码的运算结果,以便稍后使用。这种临时变量应该只被赋值一次。如果它们被赋值超过一次,就意味它们在函数中承担了一个以上的责任。如果临时变量承担多个责任,它就应该被替换(剖 解)为多个临时变量,每个变量只承担一个责任。


    最好一个临时变量只是承担一个责任。

    作法(Mechanics)

    · 在「待剖解」之临时变量的声明式及其第一次被赋值处,修改其名称。
    Ø 如果稍后之赋值语句是「i = i +某表达式」形式,就意味这是个集用临时变量,那么就不要剖解它。集用临时变量的作用通常是累加、字符串接合、写入stream或者向群集(collection)添加元素。

    · 将新的临时变量声明为final。

    · 以该临时变量之第二次赋值动作为界,修改此前对该临时变量的所有引用点,让它们引用新的临时变量。

    · 在第二次赋值处,重新声明原先那个临时变量。

    · 编译,测试。

    · 逐次重复上述过程。每次都在声明处对临时变量易名,并修改下次赋值之前的引用点。

    例子:

    下面范例中我要计算一个苏格兰布丁(haggis)运动的距离。在起点处,静止的苏格兰布丁会受到一个初始力的作用而开始运动。一段时间后,第二个力作用于布丁,让它再次加速。根据牛顿第二定律,我可以这样计算布丁运动的距离:
    
     
    
     double getDistanceTravelled (int time) {
    
         double result;
    
        double acc = _primaryForce / _mass;        //译注:第一次赋值处
    
         int primaryTime = Math.min(time, _delay);
    
         result = 0.5 * acc * primaryTime * primaryTime;
    
         int secondaryTime = time - _delay;
    
         if (secondaryTime > 0) {
    
             double primaryVel = acc * _delay;        //以下是第二次赋值处
    
           acc = (_primaryForce + _secondaryForce) / _mass;        
    
             result +=  primaryVel * secondaryTime + 0.5 * acc * secondaryTime * secondaryTime;
    
         }
    
         return result;
    
     }
    


    步骤:1:在函数开始处修改这个临时变量的名称,并将新的临时变量声明为final。接下来把第二次赋值前对acc变量所有的引用变为新的临时变量;最后在第二次赋值处重新声明acc变量。

    double getDistanceTravelled (int time) {
    
           double result;
    
          final   double primaryAcc  = _primaryForce / _mass;
    
           int primaryTime = Math.min(time, _delay);
    
           result = 0.5 * primaryAcc * primaryTime * primaryTime;
    
           int secondaryTime = time - _delay;
    
           if (secondaryTime > 0) {
    
               double primaryVel = primaryAcc * _delay;
    
              double acc = (_primaryForce + _secondaryForce) / _mass;
    
               result +=  primaryVel * secondaryTime + 0.5 * acc * secondaryTime * secondaryTime;
    
           }
    
           return result;
    
       }
    

    这种情况应该不会常见,如果重构的时候遇到这个问题就要这么处理。比较简单,总的来说就是一个原则:

    一个临时变量只是承担一个责任。





    展开全文
  • windows环境变量

    千次阅读 2011-11-07 22:22:02
     设置环境变量有两种方式:第一种是在命令提示符运行窗口中设置;第二种是通过单击“我的电脑→属性→高级”标签的“环境变量”按钮设置。需要注意的是,第一种设置环境变量的方式只对当前运行窗口有效,关闭运行...
  • thinkphp输出变量和常量

    千次阅读 2015-05-11 17:03:35
    打头,也是用标签的方式来写,我们常见的系统变量包括server,session,post,get,request,cookie,比如 {$Think.server.script_name } // 输出$_SERVER变量 {$Think.session.session_id|md5 } // 输出$...
  • 随机变量的分布

    千次阅读 2015-03-24 12:33:12
    离散型随机变量分布 分布 记号 概率公式 备注 二点分布 Bernoulli(P)Bernoulli(P) P(X=1)=pP(X=1)=p 二项分布 B(n,p)B(n,p) P(X=k)=Cknpkqn−kP(X=k)=C_n^kp^kq^{n-k} n重独立试验 泊松分布 Poisson...
  • windows 环境变量

    千次阅读 2013-04-09 16:25:22
    Visual Studio 2008 和 Windows 环境变量对设置 相对路径很重要,这样便于代码的移植,即使换一台计算机,代码不用更改配置,直接就能用。 可以在项目的“工具”“属性页”对话框中任何接受字符串的位置使用这些...
  • windows 环境变量综述

    2012-08-21 10:03:05
    点击“我的电脑→属性→高级”标签的“环境变量”按钮...的时候我们会看到在用户变量和系统变量中都存在某一个环境变量,比如path,那么path的值到底是用户变量中的值还是系统变量中的值,或者两者都不是呢?答案是两
  • vs 属性 环境变量

    千次阅读 2019-06-28 17:24:40
    这个路径没成功:vs2008-工具-属性页-环境变量 可以在项目的“工具”“属性页”对话框中任何接受字符串的位置使用这些宏。这些宏不区分大小写。 关于如何自己定义环境变量详见我的另一文章:...
  • 关于Windows的环境变量

    千次阅读 2008-10-03 15:42:00
    对XP来说常见变量有 %windir% 一般是c:/windows %ComSpec% 一般是c:/windows/system32/cmd.exe %system%不是windows内置的环境变量,是用户指定的变量,可能是定义到c:/windows/system32 如何获取系统变量: 1....
  • 数据预处理之变量变换

    千次阅读 2019-11-06 21:36:49
    在学习「数据挖掘导论」的数据预处理时,里面谈到了变量变换,我联想到了在基因表达量分析时的常见操作,例如FPKM,TPM,CPM,log对数变换。 比如说在文章里面会见到如下的描述 The size factor of each cell was ...
  • 我们也可以理解为,变量就像一个购物袋,我们可以用来装苹果、榴莲(当然也可以用来装玫瑰),需要注意的是,一般情况下一个变量只能装一个(不要太贪心)值,除非是复合变量(后面变量类型时会介绍),当我们放进去...
  • NewStart桌面操作系统中常用的环境变量有 PATH、HOME、LOGNAME 等。 l PATH 指定命令的搜索路径; l HOME 指定的是当前用户主目录; l LOGNAME 指定的是当前用户的登录名; 提示:除了以上常见的环境变量,...
  • Perl 常用特殊变量

    2017-11-07 11:19:25
    表 A-2 文件句柄 $% 当前选中文件句柄的当前页码 $= 当前选中文件句柄的...表 A-3 块内局部变量 $1..$9 含有与应用对应的一组括号的子记忆模式 。( 等效于 \1..\9 ) $& 上一次与模式相匹配的字符串 ( 等效于 sed 编辑
  • Visual Studio 2008 和 Windows 环境变量对设置 相对路径很重要,这样便于代码的移植,即使换一台计算机,代码不用更改配置,直接就能用。 可以在项目的“工具”“属性页”对话框中任何接受字符串的位置使用这些宏...
  • 原文章标题:机器学习中的特征工程——分类变量的处理 作者:CDA数据分析师培训 链接:https://www.jianshu.com/p/d63c0dbe7f3c 来源:简书 介绍关于机器学习中的特征工程关于分类变量的处理。 分类变量 概念 ...
  • LANG变量的设置

    千次阅读 2016-05-18 23:20:38
    其中LANG变量是language的简称,稍微英语基础的用户一看就看出来这个变量是决定系统的默认语言的,即系统的菜单、程序的工具栏语 言、输入法默认语言等。SYSFONT是system font的简称,决定系统默认用哪一种字体...
  • Visual Studio 2008 和 Windows 环境变量对设置 相对路径很重要,这样便于代码的移植,即使换一台计算机,代码不用更改配置,直接就能用。 可以在项目的“工具”“属性页”对话框中任何接受字符串的位置使用这些宏...
  • 然而要获得一个类的对象需要两步, 第一, 必须声明该类类型的一个变量,这个变量没有定义一个对象,它只是一个能够引用对象的简单变量。 第二,该声明要创建一个对象的实际物理拷贝,并把对于该对象的引用赋给该...
  • Gurobi添加变量addVar()和addVars() addVar() 一次增加一个变量 addVars() 一次增加多个变量 addVar() 命令行: addVar ( lb=0.0, ub=GRB.INFINITY, obj=0.0, vtype=GRB.CONTINUOUS, name=" ", column=None ) lb ...
  • php变量的定义与使用

    2016-12-04 15:45:17
    1.”var_dump”函数可以将我们的变量的数据类型(后面小节会做介绍)显示出来。 $var_name = "苹果"; $n =10; var_dump($var_name); var_dump($n); ?> 输出的结果是 string(6) "苹果" int(10) 2....
  • axure中的变量及函数

    千次阅读 2015-08-10 16:41:09
    axure的变量设置是为了完成一些逻辑上处理,例如从26个字母中随机取出四个字母作为验证码: a.用随机数定位数字,0-26中随机找到一个数字 b.根据0-26个位置找出相应的字母 c..4个一组合就可以了。
  • 出品 | CDA数据分析研究院,转载需授权 @[toc] 本文将介绍关于机器学习中的特征工程关于分类变量的处理。 分类变量 概念 顾名思义,分类变量用于表示类别或标签。...然而,与数值变量不同,分类变量的值...
  • 常见概率分布介绍

    千次阅读 2019-07-11 18:44:38
    常见概率分布 Bernoulli分布 Bernoulli分布是单个二值随机变量分布, 单参数ϕ​\phi​ϕ​∈[0,1]控制,ϕ​\phi​ϕ​给出随机变量等于1的概率. 主要性质: P(x)=px(1−p)1−x={p if x=1q if&...
  • 1. 变量的定义 1.1 变量名可以由字母、数字、下划线组成,但数字不能作为变量名的第一个字符。 1.2 通过赋值符号“=”来定义变量的值,e.g: myname='test', 字符串类型,不解析任何字符 myname="abcd", 双引号内部...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 33,548
精华内容 13,419
关键字:

常见有界变量