C语言笔记

这篇博客详细介绍了C语言中的指针相关知识,包括sizeof和strlen的区别、字符指针的创建和修改、指针运算、二维数组、函数指针、结构与联合、位字段、输入输出以及文件操作等。博主强调了指针运算的规则,如指针加减运算与自增自减运算符的结合,并探讨了结构体中的空洞。此外,还提到了C语言中字符串处理、内存分配和文件操作的相关函数。
摘要由CSDN通过智能技术生成

琐碎知识点

  1. %d,有符号整型数,字节数看机器,本机4字节

    printf("%d\n",0x7fffffff);//2147483647 2e31-1 32位 4字节
    printf("%d\n",0xffffffff);//-1 最高位是符号位

    from K&R

    此外,
    %ld long类型
    %lld longlong类型
    宽度和精度可以用 * 表示,如:
    printf("%.*s", max, s);
    其中max为int类型,表示从字符串s中打印最多max个字符。
    printf("%m.nf",xxx)表示**一共最小**m列,小数点后面n位。
    .表示之前一共最小是之前的那个整数,不够则用空格补上,-是右边补空格。多了则无影响。

    printf返回值为打印的字符数。

    printf使用第一个参数判断后面参数的个数及类型。
    需注意:

    printf(s); /* FAILS if s contains % */
    printf("%s", s); /* SAFE */
  2. 返回值非int的函数用前需声明(除非函数声明在使用之前)。
  3. 如果函数返回值大于1个,可以考虑传入待求值地址的指针,在函数体内对指针指向的数据进行赋值,来达到“返回”多个值的目的。
  4. 本机64位,int 4; long 4; long long 8;
  5. 变量名不占空间,用来标识某个指定了大小的内存块。
  6. 指针名、数组名、函数名、结构名就是地址,它们分别表示指针所指向元素的地址、数组的首地址、函数的入口地址、结构的入口地址。
  7. 类和结构只有事例化时才为它分配空间,从而不能用取地址符号&来获得类名或结构名的地址。
  8. 指针取指向的值运算符‘*’优先级低于:结构运算符‘.’和‘->’、下标符‘[]’、函数调用符‘()’。这四个同时出现遵循从左至右的结合原则。其他优先级见:百度百科
  9. 结构长度不等于结构各成员长度的和。因为不同对象有不同的对齐要求,所以,结构中可能会出现未命名的“空穴。”
  10. 字符指针数组长度获取方法:
    sizeof(argv)/sizeof(char*))
  11. char *p 和char a[20]是不同的,前者p指针变量本身在栈上,指向的内容仅为一个字符;a只是个数组名,本身不占运行时程序的空间,只是在源程序中用来标记一个字符数组(即其首地址),而数组也是存储在栈上的。
  12. 文件目录路径获取方法:

    include <direct.h>
    main()
    {
    char buffer[100];
    printf("%s",getcwd(buffer,100));
    }
  13. 递归时,函数不断加到栈中,处理不好可以会栈溢出(常常是因为基线条件没弄好,不然很少发生)。
  14. 堆栈申请方式:
    • stack: 由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间
    • heap: 需要程序员自己申请,并指明大小,
      • 在c中malloc函数,如p1 = (char *)malloc(10);
      • 在C++中用new运算符,如p2 = new char;
        但是注意p1、p2本身是在栈中的。
  15. for循环里面最后用++i效率比i++高,因为后者还要保存原值。
  16. const的修饰问题:
    如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向的为常量;如果const位于星号的右侧,则const修饰的是指针本身,即指针本身是常量
  17. 非常量作为常量函数的参数会编译出错;反之可以。这意味着写函数时,形参尽可能加上const,好让调用时无论是常量还是非常量都编译通过。

指针相关

sizeof和strlen的区别:

  • strlen通过’\0’识别数组的结束,返回元素个数;sizeof通过分配的内存,返回数组字节数,而不是指向数组的指针的长度;
  • strlen编译阶段不处理;sizeof是关键字,是在编译阶段处理的,也就是说程序没有运行前,sizeof(arr)就被替换成了一个固定的常量,保存在了.out文件中了。
char str[20]="0123456789"
int aa=strlen(str);
int bb=sizeof str;
printf("aa=%d\n",aa); //aa=10
printf("bb=%d\n",bb); //bb=20

char str1[]="0123456789"
int cc=sizeof str1;
printf("cc=%d\n",cc); //bb=11,最后多个'\0'

int array[20]={
  1,2,3,4};
int ai=strlen(array); //实质上没有意义,但可以看看结果
int bi=sizeof array;  //可以不加括号,因为sizeof不是函数,而是编译器提供的操作符
printf("ai=%d\n",ai); //ai=1,1的第二个字节为0,等于字符串结束符'\0'
printf("bi=%d\n",bi); //bi=80,内存总共分配的字节数
printf("size=%d\n",bi/sizeof(array[0]));//数组个数size=20

字符指针

  • C语言没有提供将整个字符串作为一个整体进行处理的运算符。(K&R. P89)
字符指针创建
char *p = "how are you doing?";
printf("p=%d\n",p);  // p=4210824,首元素'h'地址
printf("*p=%c\n",*p);//*p=h,首元素'h'
用指针进行字符修改
char ap[] = "how are you doing?";
*(ap+1)='w';//或者 ap[1]='w';
printf("ap[1]=%c\n",ap[1]);// ap[1]=w,修改成功

char *p = "how are you doing?";
*(p+1)='w'; //运行到此停住了,修改不了
printf("*(p+1)=%c\n",*(p+1));

第一种方式:
"how are you doing?"保存在栈空间数组里,数组名为ap,函数名为数组的首地址。可以通过*(ap+1)='w';或者 ap[1]='w';的形式来修改数组内容。

第二种方式:
char *p = "how are you doing?";
"how are you doing?"保存在文字常量区,该数据不能修改,默认有只读属性。由指针p指向,不能通过指针p来修改此值。

  • void类型的指针可以存放指向任何类型的指针,但它不能间接引用其自身。(K&R. P80)
  • C语言是以传值的方式将参数值传递给被调用函数,因此,被调用函数不能直接修改主调函数中变量的值。(K&R. P81)
//无效的swap函数
void swap(int a, int b)
{
    int temp = a;
    a = b;
    b = temp;
}

//有效的swap函数
void swap_p(int *a, int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

指针大小

32位机4字节;64位机8字节

char ap[] = "how";
printf("%d\n",sizeof(ap));     //4,数组大小
printf("%d\n",sizeof(&ap[0])); //8,指针大小,获取第一位指针,不能直接用ap来获取指针大小
printf("%d\n",sizeof(ap+1));   //8,指针大小

指针运算

  • 指针加1,结果是对该指针增加1个储存单位—-指针指向的数据类型所占的内存的字节数。不同类型的指针加1后,增加的大小不同。
  • 对于二维数组,创建时列数必须声明,行数可以不用(可以理解为一维数组默认列数为1,故不用声明)。
char arr[][3] = {
  {1,2,3},{4,5,6}};
printf("arr=%d\n",arr);    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值