C语言提高

C语言提高

1. typedef的用法

  • 用于给数据类型定义别名
  • 一般用于给结构体简化名称
  • 也可增加代码移植性(我觉得将来用不到)

2. 函数与void

a.返回值类型

    void function(){
        XXXXXX;
        return 3;
    }

C语言对函数的检查不够严格,上面函数返回值写void,但是函数体里面去写了返回值,这显然是不正确的做法,但是在实际的运行过程中,却未必会报错,甚至没有任何警告

  • 如果不写void,编译器会自动根据该函数是否存在返回值而默认添加返回值类型,但并不总是能够返回正确的结果,在有的编译器对于部分返回值,会出现意想不到的错误
  • 如果写void返回值,而返回值类型并不是void,在不使用该返回值而仅仅是调用该函数的情况下,编译器只有警告,但可以正常运行。

b.传入参数

int f(void)
{
    printf("函数调用\n\n");
    return 5;
}

int main(void)
{
    f(2);

    system("pause");
    return 0;
}

C语言对传入的参数的检查不严格

  • 在定义函数传参为void时,调用函数是传入一个或多个参数只产生警告,而不报错,函数可以正常运行

3.typeof()不是一个函数

a.本质不是一个函数,而是一个操作符

b.使用方法

int main(void)
{
    int a = 10;

    printf("szieof int = %zd\n", sizeof(int)); //对数据类型的使用方式
    printf("szieof a = %zd\n", sizeof(a)); //对变量的操作方式1
    printf("szieof a = %zd\n", sizeof a); //对变量的操作方式2

    system("pause");
    return 0;
}

c.返回值类型—unsigned int

if (sizeof(int) - 10 > 0) //True
        printf("sizeof(int) - 10 > 0\n");

堆和栈

1.栈的生长方向

栈底(高地址)–> 栈顶(底地址)

2.数据存储方向 — 小端对齐

高位(低地址) --> 地位(高地址)
即:数据由右向左存储

3.在堆中分配与管理内存空间(动态分配内存)

以分配四百个int大小的字节空间为例

  • malloc()

不会为这快空间初始化数据

int * a = malloc(sizeof(int)*100)
  • calloc()

为这块空间初始化数据为0

int * a = calloc(100, sizeof(int))
  • realloc()

不会为新开辟的空间初始化数据
新的内存分配机制有三种:
机制一,如果空间变小:截断后面的数据,前面的空间构成新的内存空
机制二,如果空间变大:该内存后续空间充足,直接将内存空间往后延伸扩展,指针指向地址不会发生改变
机制三,如果空间变大:该内存后续空间不足,开辟新的空间,将原来数据拷贝到新空间,指针指向地址发生改版

???
虽然新开辟空间并没有被初始化,但是值大到一定程度时会发现,相当一部分数值为0,而且我在测试过程中,内存地址似乎一直没有改变,这是通过vs2017测试的结果,以上两点令我疑惑不解
???

int * a = malloc(sizeof(int)*95)
a = realloc(a, sizeof(int)*100)

堆与栈注意事项

1.不要用函数返回临时变量的地址

在使用函数返回函数体内的临时变量之后,该临时变量的内存空间已经被释放,i得到的地址已经没有意义了,及时系统为该值作了一次保留,但是在第二次使用时就会变成一个意料之外的固定数值

int * f(void) {
    int a = 10;

    return &a;
}

int main(void)
{
    int * i = f();

    printf("%d\n", *i); // i = 10, 系统为变量做了一次保留,第二次使用值就发生了改变
    printf("%d\n", *i); // i = *********(两串相同的长数字)
    printf("%d\n", *i); // i = *********

    system("pause");
    return 0;
}

2.不要将空指针作为实参传递给被调函数

在主调函数中的指针如果没有指向地址,作为参数传给被调函数时,背调函数的形参值依然为NULL,修改被调函数的指针地址并不能修饰到主调函数。
解决办法:形参设为高级指针,将指针变量的地址作为地址传递

const

  • 在函数体内(包括主函数)用const修饰的变量为伪常量,在有些时候并没有常量所拥有的功能,虽然不能直接修伪常量的值,但是可以通过创建一个指针指向该常量,修改指针地址的值,就可以达到修改常量值得目的
  • 在函数体外用const修饰的变量是真正的常量,不能被修改,即使通过指针的方法修改,语法可以通过,但是运行时会中断
  • const修饰函数形参,使传递给函数的值不可修改(可以防止指针传递过来的数据被修改)

字符串常量

关于字符串常量的处理并没有设立标准,不同编译器有不同的实现方案

  • 有的编译器把相同的字符串只设定一个地址,有的编译器则不作这样的优化
  • 有的编译器可以修改字符串中的某个字符,有的编译器则不可以
  • 由指针定义地字符串为字符串常量,存放在栈中,不可被修改
    char * str = "Hello!"; //存放在栈中

指针

杂项

1.不能通过对指针赋值正整数的方法给指针指定一个地址,这是非法的,否则程序会在运行时中断

2.指针多指向的内存地址发生偏移之后,就不能利用该指针对原空间进行释放了,否则程序会在运行时中断

野指针

  • 使用为未初始化的指针
  • malloc被free之后,指向的这个内存的指针的值没有被设为NULL
  • 函数结束后,函数体内的静态变量的内存被释放,指向的这个内存的指针的值没有被设为NULL
    注:空指针(值为NULL的指针)可以被释放(free),野指针会运行报错

字符串

1.字符串的定义方法

    char a[] = { 'h' , 'e', 'l', 'l' , 'o', '!', '\0' }; //最后需要添加\0结束字符
    char b[10] = { 'h' , 'e', 'l', 'l' , 'o', '!' }; //默认没有赋值的后面几个字符都是\0
    char * c = "hello!";
    printf("%c\n", *c);
    printf("%c\n", *b);
    printf("%c\n", *a);
  • 未指定长度的字符串数组必须在最后添加结束自负‘\0’,否则使用或者输出是会出现乱码
  • 指定长度的字符的数组默认没有赋值的后面几个字符都是‘\0’
  • 变量名保存字符串的第一个字符的地址,可以用*(变量名+n)取出其中的每一个字符

2.字符串的三种拷贝方法

a.通过数组方式获取单个字符逐个修改

void strcp1(char * newstr, char * sourcestr)
{
    int len = strlen(sourcestr); 
    for (int i = 0; i < len; ++i)
    {
        newstr[i] = sourcestr[i];
    }
    newstr[len] = '\0'; //目标是个数组,其实可以不用加‘/0’

    return;
}

b.通过指针操作获取单个字符地址逐个修改

void strcp2(char * newstr, char * sourcestr)
{
    while (*sourcestr != '\0')
    {
        *newstr = *sourcestr;
        newstr++;
        sourcestr++;
    }
    *newstr = '\0'; //目标是个数组,其实可以不用加‘/0’

    return;
}

c.类似于b,是一种更简洁更难理解的方法

    while (newstr++ = sourcestr++){}

3.sprintf()&menset()

a.sprintf()作用

  • 拼接字符串

  • 数字转字符串

b.menset()作用

  • 格式化字符串数组
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值