笔者记不住的一些注意事项和一些操作符的运用与君分享(基础C)

简介: 笔者记不住的一些注意事项和一些操作符的运用与君分享(基础C)

一.万恶的逗号表达式(逗号表达式所'要的是'最后一个值)


首先笔者对于要的是做了一个引号,😂,因为我自己无数次在这里犯错,我十分清楚逗号表达式对于所在表达式是只要最后一个值,但是往往会忘记前面的式子也会运算并将结果体现在后面的式子中。可能大家不太理解,我举个例子:

int main()
{
  //+的优先级高于+=
  int a, b, c;
  a = 5;
  c = ++a;//6
  b = ++c, c++, ++a, a++;//c=8,a=8,b=7  经典逗号表达式,这里就有坑,首先b=a++,其次这里运算后b应该等于7,前面的++a会使得a变成7,然后由于后面的a++是后置,所以b=7,而注意在后续运算中a=8了
  b += a++ + c;//a=9,c=8,b=23,a先以原本值参与计算再在后面的式子以a+1的值参与运算
  printf("a=%d,b=%d,c=%d\n", a, b, c);//9,23,8
}

这是比较经典的一道题,也是我摘录过来的。挺有意思的


二.让人迷糊糊的大端小端


大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址 中; 小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地 址中。--每次读到定义我都很迷,就算理解了过两天就有分不清楚了。我按照自己浅薄的理解简要梗概一下。


小端存储是小的一端先存入低地址处,再依次向高地址处存放;"机器"在读取打印时是先打印高地址再打印低地址例如0x11223344  打印由高地址到低地址就是0x11223344,而在调试中是44332211(观者可以尝试)。


笔者简要绘制了一个图形:


1669210130519.jpg


存储是 44 33 22 11 地址由低到高,进行更改也是由低到高。某度曾经出过如何检测机器是如何存储的。


这里给出两个方法:


1.常用方法

int main()
{
  int a=0x11223344;//验证是如何存储
  char*pc=(char*)&a;
  *pc=0;//由于强制类型转换只操作char*大小
  printf("%x\n",a);//%x代表是16进制
  return 0;
}

2.联合体方式

int check_sys()
{
 //采用联合体是借助联合体的特性来操作
 union
{
 int i;
 char c;
}un;
un.i=1;
return un.c;
}
int main()
{
 int ret=check_sys();
 if(ret==1)
 printf("是小端\n");
 else
 printf("是大端\n"); 
 return 0;
}


三.i是局部变量的话是随机值,全局变量不初始化默认是0;整形在和无符号数进行比较的时候,整形要转化成无符号数进行计算。


也用😳代码解释吧。

int i;
int main()
{
  i--;
  if (i > sizeof(i))//首先i全局变量默认是0,其次整形在和无符号数进行计算的时候要转换成无符号数参与计算,故-1特别大;
  {
  printf(">\n");
  }
  else
  printf("<\n");
    return 0;
}

输出为>


四.运算时容易忽略的整形提升


别忘了运算时的整型提升,对于非int型(cpu的通用寄存器长度)进行运算要进行整型提升,非整形数打印整形整型提升不够的位补符号位,

无符号位直接高位补零:

整型提升的例子:

int main()
{
  char a = 0xc6;
  short b = 0xc600;
  int c = 0xc6000000;
  if (a == 0xc6)
  printf("a");
  if (b == 0xc600)
  printf("b");
  if (c == 0xc6000000)
  printf("c");
  return 0;//只能打印出来c,因为a和b分别是char和short类型,所以在运算中会整型提升,发现值不再相等
}

第二大块:操作符的一些编码题目(有时操作符真的很有用,如果观者遇到一些考察"二进制的题目"而百思不得其解不妨想象底层的操作符,🌹)


1.统计二进制中1的个数


方法一:%2  /2  因为是二进制存储,故%2下来只有0和1两种情况。类似于十进制的。不过要注意%的对象只能是整形(笔者栽过坑)

int count_one_bit(unsigned int*get)
{
 int count=0;
 while(*get)
 {
  if(*get%2==1)
  {
   count++;
  }
   *get=*get/2;
 }
 return count;
}
int main()
{
 int get=0;
 scanf("%d",&get);
  int count=count_one_bit((unsigned int*)&get);//转化为unsigned int 的原因是因为如果仅仅整形,负数是无法计算的,故要转换
 printf("count=%d\n",count);
 system("pause");//停一下
 return 0;
}


2.法二


32个bit位,一个一个扣下来按位与&,右移操作符 按位与&

int count_one_bit(unsigned int*get)
{
int i=0;
int count=0;
for(i=0;i<32;i++)
{
if((*get)>>i&1==1)
count++;
}
return count;
}
int main()
{
int get=0;
scanf("%d",&get);
int count=count_one_bit((unsigned int*)&get);
printf("count=%d\n",count);
return 0;
}

3.法三(最优也是最难以理解)


//实现原理-以一个数字13为例
//1101    n
//1100-12 n-1
//n=n&(n-1),按位与后最右边1消失了
///1100 m --12
//1011(m-1)--11
//m与m-1 按位与后变为1000
//1000
//0111 按位与后变为0000
//n=n&n-1后就会让二进制序列里右边的1消失,执行几次就有几个1
int count_bit_one(unsigned int*get)
{
while(*get)
{
*get=*get&(*get-1);
count++;
}
return count;
}
int main()
{
int get = 0;
scanf("%d", &get);
int count = count_bit_one((unsigned int*)&get);
printf("count=%d\n", count);
return 0;
}


使用按位异或 ^

求二进制中不同位的个数

编程实现两个二进制数m和n中,有多少个位(bit)不同

int count_dif_bit(unsigned int*m,unsigned int*n)
{
  //先按位异或得到一个数,在进行求这个数有多少个1,即可解得
  int count = 0;
  unsigned int tmp = (*m) ^ (*n);
  while(tmp)
  {
  //用上文的最优解法
  tmp = tmp & (tmp - 1);
  count++;
  }
  return count;
}
int main()
{
  //避免代码冗余,直接设为无符号数类型
  unsigned int m = 0;
  unsigned int n = 0;
  scanf("%u%u", &m, &n);//%u是返回无符号数类型
  int count= count_dif_bit(&m, &n);
  printf("count=%d\n", count);
  return 0;
}

打印二进制的奇数位和偶数位

题目内容:获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出来

void Print(int* m)
{
  int i = 0;
  printf("奇数位:\n");
  for (i = 30; i >=0 ; i-=2)
  {
  //打印奇数位
  printf("%d ", (*m) >> i & 1);
  }
  printf("\n");
  printf("偶数位:\n");
  for (i = 31; i >=1; i -= 2)
  {
  //打印偶数位
  printf("%d ", (*m) >> i & 1);
  }
  printf("\n");
}
int main()
{
  int m = 0;
  scanf("%d", &m);
  Print(&m);
  return 0;//1011--00000000
}

这些内容是笔者希望分享给大家,让大家一样不再犯错。希望各位能有所收获吧!!🌹

相关文章
|
8月前
|
算法 Java C语言
【c语言基础题】— —第一版,可当作日常练习和期末复习,有奇效哟!
【c语言基础题】— —第一版,可当作日常练习和期末复习,有奇效哟!
|
8月前
|
缓存 前端开发 JavaScript
整会promise这8个高级用法,再被问倒来喷我
整会promise这8个高级用法,再被问倒来喷我
整会promise这8个高级用法,再被问倒来喷我
|
5月前
|
程序员 C# 开发工具
C#☀️原来高级程序员是这样使用 & 操作符
C#☀️原来高级程序员是这样使用 & 操作符
|
存储
用处巨广的操作符,快来学学叭(C语言版)
用处巨广的操作符,快来学学叭(C语言版)
83 1
《C++避坑神器·十二》函数返回值不能被赋值问题
《C++避坑神器·十二》函数返回值不能被赋值问题
111 0
|
编译器 C++
《C++避坑神器·十八》运算符重载,小白也能看懂
《C++避坑神器·十八》运算符重载,小白也能看懂
56 0
|
前端开发 JavaScript C语言
带你读书之“红宝书”:第三章 语法基础(中)之 3.5操作符④
带你读书之“红宝书”:第三章 语法基础(中)之 3.5操作符④
101 0
带你读书之“红宝书”:第三章 语法基础(中)之 3.5操作符④
|
存储 前端开发 JavaScript
带你读书之“红宝书”:第三章 语法基础(中)之 3.5操作符②
带你读书之“红宝书”:第三章 语法基础(中)之 3.5操作符②
104 0
带你读书之“红宝书”:第三章 语法基础(中)之 3.5操作符②
|
前端开发
带你读书之“红宝书”:第三章 语法基础(中)之 3.5操作符③
带你读书之“红宝书”:第三章 语法基础(中)之 3.5操作符③
81 0
带你读书之“红宝书”:第三章 语法基础(中)之 3.5操作符③
|
存储 SQL 数据安全/隐私保护
SQL存储过程的详细用法,不信你看不懂(下)
时不时有小伙伴私聊我这个存储过程怎么这么难啊? 说实话,我刚开始学SQL也觉得写存储过程可能是整个SQL开发中最难的了。因为存储过程简单起来可以只写一句SELECT就行,复杂起来写几天几夜也未必能写完(夸张了图片)。 但也不是说学不会,今天就给大家好好恶补一下存储过程的一些常规用法,一些非常规用法实在是太多了,这里就不一一列举了。
SQL存储过程的详细用法,不信你看不懂(下)