《c和指针》学习日记

        更安全的方法:

#if 0
    statements
#endif
  • 函数声明:函数返回值类型  函数名(输入参数)
  • 数组参数调用:引用,传地址调用
  • 标量和常量:值传递
  • 函数内部定义的变量均为局部变量,其他函数无法根据名字访问它们
  • 字符串:以nul(全大写)结尾

        字符串常量:"hello",占用6个字节, h e l l o 以及nul(全大写)

        

  • printf格式代码

        %d:十进制打印整形值

        %o:八进制打印整形值

        %x:十六进制打印整形值

        %g:打印浮点值

        %c:打印字符

        %s:打印字符串

        \n:换行

  • puts函数:把指定的字符串写到标准输出并在末尾加上一个换行符

  Ch3.数据-----------20250322

   1.基本数据类型(4种)

        整形、浮点型、指针、聚合类型

  • char类型本质上是小整数型值 
  • 字符串常量:空字符串(“ ”)依然存在NUL字节作为终止符      

        使用时作为“指向字符的常量指针”

    2.基本声明

  • 变量声明

        signed关键字一般只用于char类型,其他整型在缺省是默认有符号数,但是char类型可以是signed char或者是unsigned char

  • 指针声明

        int *a------------a被声明为int*类型的指针

  • 隐式声明

        函数为声明返回值类型,默认为整型

    3.typedef

   

     4.常量

  • const

        int const a;等同于 const in a;

        const用于指针:看const修饰谁,离谁近

        int *p;---指向整型的指针

        int const  *p;---指向整型常量的指针常量指针(指针的值p可以修改,指向的值*p不能改)

        int *const p;---指向整型的指针常量(指针的值p不可更改,指向的值*p可以更改)

        int const * const p;---指向整型常量的指针常量(指针的值和所指向的值都不能改)

        指针常量(Pointer to const)与常量指针(const pointer)

        可以直接从英文来区分二者

        

  • 字符常量
  1. 必须使用单引号
  2. 只能包含一个字符
  3. 可以是普通字符、转义字符、或者ASCII码值对应的字符

        5.作用域

  • 四种类型:文件作用域、函数作用域、代码块作用域、原型作用域
  • 标识符声明的位置决定作用域

        文件作用域:在代码块之外声明的标识符都有文件作用域(图中声明1、2、4)

        函数作用域:只适用于语句标签,语句标签用于goto语句(不太理解)

        代码块作用域:花括号之间的语句

        嵌套的变量共享一个内存地址

        原型作用域:只适用于在函数原型中声明的参数名(声明3、8)声明5不是吗?

  • 链接属性:external、internal、none

        只要变量不是声明于代码块或者函数定义内部,它在缺省情况下的链接属性均为external

        

        如果某个声明具有external链接属性,在它前面加上static关键字可以将链接属性变为internal

6.存储类型

        对于代码块内部声明的变量,加上关键字static,存储类型从自动变为静态变量

        修改存储类型不表示修改变量的作用域

  • 静态变量:在任何代码块之外声明的变量,不属于堆栈的内存,存储于全局数据区
  • 自动变量:在代码块内部声明,存储于堆栈中(程序执行离开该代码块时,自动变量自动销毁,因此在函数被反复调用时,变量的地址可能会不同)

            关键字register可用于自动变量的声明,表明变量存储于硬件寄存器而不是内存中(寄存器变量访问效率比内存变量高)

内存分配:

  1. text段:存放程序的代码/指令,不存放变量
  2. data段:存放已初始化的全局变量和静态变量
  3. variable:不是一个标准的程序段名称
  4. bss段:存放未初始化的全局变量和静态变量,在程序加载时会自动初始化为0

7.static关键字

链接属性和存储类型总结


Ch4.语句

1.while语句

  • while循环中使用break语句,永久终止循环
  • 使用continue语句,永久终止当前的那次循环(?)

        这两条语句用于嵌套循环内部,只对最内层的循环起作用

2.for语句

3.do语句

4.switch语句

  • switch语句中的expression必须为整型值
switch( expression )
       statement-list

statement-list:
case constant-expression

        当expression的值与所有case的值不匹配时,跳转default子句


Ch5.操作符和表达式

1.++和--的前缀和后缀区别

++i:操作数的值在修改之后返回这个值

i++:操作数的值在修改之前返回这个值

2.条件操作符:?:三参数

        expression1 ? expression2 : expression3

        expression1的值为真,表达式等于expression2的值

        expression1的值为假,表达式等于expression3的值,且不对expression2进行求值

3.逗号操作符:

4.移位运算:

        可以用%来判断某一位是否为非零

        具体操作:value%2!=0

        %:输出余数,只有整型数能使用

5.操作符优先级:

 


Ch6.指针

1.内存和地址

  • 边界对齐问题:整型值存储的起始位置只能为特定的字节,通常为2或4的倍数
  • 声明一个指针变量并不会自动分配任何内存,在对指针间接访问前,指针必须进行初始化

2.NULL指针

        表示某个特定的指针目前并未指向任何东西

        对NULL指针解引用操作是非法的

3.指针运算

        非法操作:指针减去一个整数后,结果在数组的第一个元素之前

        合法操作:指针加上一个整数后,结果在数组最后一个元素后面的那个内存位置(但不能对指针进行间接访问,且加法运算不能再往后加)

      1.  指针+整数=?

        与指针所指向的类型大小有关(注:所有指针均占用4个字节)

                float占据4个字节

      2.  指针-整数=?

        只有当两个指针都指向同一个数组中的元素时,才允许一个指针减去另一个指针

        与上一种运算有所不同,指针的差值与数据类型无关,结果是指针的距离,不需要乘上元素所占用的字节

      3.关系运算

        前提:指向同一个数组的元素


Ch7.函数

1.函数定义与声明

  •  return语句:

        return语句允许从函数体的任何位置返回,并不要求一定在函数体的末尾

        函数也可以没有返回值,如vois类型函数

  • 函数原型(声明)

        没有参数的函数原型: int  *func(void)

        缺省认定:程序调用一个没有原型的函数时,默认调用的函数返回一个整型的值

  • 函数的参数

           C语言中所有参数都是传值调用

        两个规则:1.传递给函数的标量参数是传值调用

                           2.传递给函数的数组参数在行为上类似于传址调用

2.递归

        使用字符常量比整型常量的程序可移植性更高

  • 递归函数:直接或间接调用自身的函数

        递归调用会保存在堆栈中的变量值,与循环不同【参数被压到堆栈中,为局部变量分配内存空间,寄存器的值必须保存】---->递归运行带来的开销,往往采用迭代实现效率会更高

3.可变参数列表(不太明白)

可变参数列表通过宏来实现,定义于stdarg.h文件中

4.函数指针

        向函数传递指针:有缺陷,函数可以对指针变量进行修改,防止这样可以在函数原型中使用const关键字。


Ch8.数组

1.一维数组

  • 数组名:指针常量,也是数组第一个元素的地址,类型取决于元素的类型

        数组名不用指针常量表示的两种情况

        数组名作为sizeof操作符或者单目操作符&的操作数时(sizeof返回整个数组的长度而不是指向数组的指针的长度

      例子:

  • 数组和指针

        二者区别:1.声明数组时,根据指定的元素数量为数组保留内存空间,然后再创建数组名

                          2.声明指针变量时,编译器只为指针本身保留内存空间不为任何整型值分配空间

        数组名参数传递给函数:

int strlen(char *string);
int strlen(char string[]);

两个声明等价,但不代表指针和数组名相等

        

  • 数组初始化:

        字符数组初始化

2.多维数组

  • 数组名:一维表示指向元素类型的指针,二维表示指向某个一维数组的指针
  • 下标:

           *(matrix+1)==matrix[1]

          *(matrix[1]+5)==matrix[1][5]

        指向二维数组的指针:二维数组第二个下标不可省略

int vetor[10], *vp=vector;
int mat[3][10], (*mp)[10]=mat;

  • 多维数组在函数中传递:
一维数组函数传递:
int  vet[10];
...
fun1(vet);
函数原型:
void fun1(int *v); 或者是
void fun1(int v[]);

二维数组函数传递:
int  matrix[3][10];
...
fun2(matrix);
函数原型:
void fun2(int (*mat)[10]); 或者是
void fun2(int mat[][10]);

3.指针数组

        定义 int *api[10];---------下标引用优先级高于间接访问

例题:


Ch9.字符串、字符和字节

1.字符串

        以NUL字节结尾,为终止符号,不是字符串的一部分,字符串长度不包含NUL字节

(不太理解)

  • 字符串长度:strlen( )--------返回size_t类型
  • 复制字符串:

         strcpy(变量,字符串常量)缺点:复制过去的字符数组长度太长会造成内存泄露

        strncpy(变量s1,常量s2,size)      当s2长度大于s1长度时,结果不会以NUL字节结尾

  • 连接字符串:strcat(变量 , 常量 )

        strncat(变量,常量,size)

  • 字符串比较:strcmp( char const *s1, char const *s2)

        s1<s2  返回小于0的值, s1>s2  返回大于0的值,相等,返回0

        strncmp( char const *s1, char const *s2, size)

2.字符串查找

  • 查找一个字符的位置

  • 查找任何几个字符

  • 查找一个子串

  • 字符转换

        大小写转换:

                返回值为大写:int toupper( in ch)

                返回值为小写:int tolower( in ch)                       

3.内存操作

        用于处理非字符串数据,因为字符串函数处理数据时遇到第一个NUL字节将停止工作


Ch10. 结构和联合

1.结构体

  • 结构是一些成员的集合,各个成员可能是不同的类型
  • 结构变量是标量类型
  • typedef可以创建一种新的类型

结构体成员访问:点操作符----(.),从左向右结合(下标和点操作符具有相同的优先级)

        如com.s------com为结构,s为成员

结构体成员间接访问:先通过指针间接访问,再使用点操作符访问成员

        (*cp).f           或者cp->f

结构的自引用:非法操作

2.不完整声明

3.结构内存分配

        字节对齐问题:每四个字节来分配内存,成员存储字节不够则另开4个字节

        结构体成员顺序不同会造成不同的空间分配

12个字节

8个字节

sizeof和foosetof

        sizeof会包含结构浪费的空间

4.传递结构和传递指针

        一般来说,传递指针效率更高,且如果希望函数修改结构的任何成员,也应该使用结构传递

        防止程序修改结构参数的唯一办法:像函数传递一份结构的拷贝

5.联合Union

        联合的所有成员引用的是内存中相同的位置

        内存占用大小:最大成员占用的字节数

        联合的初始化:初始值必须是联合中第一个成员的类型,且必须位于一对花括号{}里面


Ch11.动态内存分配

        数组被声明时,所需内存在编译时已经被分配,可以通过动态内存分配在运行时来分配内存

1.malloc和free函数

#函数原型
void *malloc( size_t size)

void free( void *pointer)

malloc函数:从内存池中取一块连续的内存,并返回一个指向这块内存的指针

注意:内存池空间不够时,malloc就返回一个NULL指针

        void*类型的指针可以转换为其他任何类型的指针

free函数:参数要么是NULL,要么是从malloc、calloc或者realloc函数的返回值

2. calloc和realloc函数

        

3. 内存泄漏

        分配的内存使用后不释放会造成内存泄漏

4.字节对齐问题

#include <iostream>

#pragma pack(push, 1) // 设置字节对齐为 1 字节,取消自动对齐
struct UnalignedStruct {
    char a;
    int b;
    short c;
};
#pragma pack(pop) // 恢复默认的字节对齐设置

struct AlignedStruct {
    char a;   // 本来1字节,padding 3 字节
    int b;    //  4 字节
    short c;  // 本来 short 2字节,但是整体需要按照 4 字节对齐(成员对齐边界最大的是int 4) 
              // 所以需要padding 2
   // 总共: 4 + 4 + 4
};

struct MyStruct {
 double a;    // 8 个字节
 char b;      // 本来占一个字节,但是接下来的 int 需要起始地址为4的倍数
              //所以这里也会加3字节的padding
 int c;       // 4 个字节
 // 总共:  8 + 4 + 4 = 16
};

struct MyStruct1 {
 char b;    // 本来1个字节 + 7个字节padding
 double a;  // 8 个字节
 int c;     // 本来 4 个字节,但是整体要按 8 字节对齐,所以 4个字节padding
  // 总共: 8 + 8 + 8 = 24
};


int main() {
    std::cout << "Size of unaligned struct: " << sizeof(UnalignedStruct) << std::endl; 
    // 输出:7
    std::cout << "Size of aligned struct: " << sizeof(AlignedStruct) << std::endl; 
    // 输出:12,取决于编译器和平台
    std::cout << "Size of aligned struct: " << sizeof(MyStruct) << std::endl; 
    // 输出:16,取决于编译器和平台
    std::cout << "Size of aligned struct: " << sizeof(MyStruct1) << std::endl;
     // 输出:24,取决于编译器和平台
    return 0;
}

刷题笔记:

1.scanf:

printf:   %在printf中为特殊字符,输出一个%需要用两个%

        printf("%%%%")----------输出结果为%%

2.强制类型转换:int<float<double(精度排序)

        int i   float f   double d

        (int)(float)i---->将i转换为float再转换为int

        (float)(int)f、(float)(double)f

        从低到高可以保持值不变,从高到低会丢失精度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

alwaysonlinee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值