c语言提高学习笔记——02-c提高03day

在学习c语言提高总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

02-c提高03day

目录:
1、堆分配内存API
2、sscanf
3、练习:查找子串
4、一级指针易错点
(1)越界
(2)指针叠加会不断改变指针指向
(3)返回局部变量地址
(4)同一块内存释放多次
5、const使用
6、指针的指针(二级指针)
(1)二级指针基本概念
(2)二级指针做形参输出特性
 (3)二级指针做形参输入特性
(4)二级指针练习
7、位运算
(1)位逻辑运算符
1)按位取反~
2)位与(AND):&
3)位或(OR):|
4)位异或:^
(2)移位运算符
1)左移<<
2)右移
3)用法:移位运算符

 

1、堆分配内存API:

 1 #include<stdlib.h>
 2 void *calloc(size_t nmemb,size_t size);
 3 功能:
 4     在内存动态存储区中分配nmemb块长度为size字节的连续区域。calloc自动将分配的内存置0 5 参数:
 6     nmemb:所需内存单元数量
 7     size:每个内存单元的大小(单位:字节)
 8 返回值:
 9     成功:分配空间的起始地址
10     失败:NULL
 1 #include<stdlib.h>
 2 void *realloc(void *ptr,size_t size);
 3 功能:
 4     重新分配用malloc或者calloc函数在堆中分配内存空间的大小。realloc不会自动清理增加的内存,需要手动清理,如果指定的地址后面有连续的空间,那么就会在已有地址基础上增加内存,如果指定的地址后面没有空间,那么realloc会重新分配新的连续内存,把旧内存的值拷贝到新内存,同时释放旧内存。
 5 参数:
 6    ptr:为之前用malloc或者calloc分配的内存地址,如果此参数等于NULL,那么和realloc与malloc功能一致
 7    size:为重新分配内存的大小,单位:字节
 8 返回值:
 9     成功:新分配的堆内存地址
10     失败:NULL

示例代码

 1 void test01(){
 2   int* pl=calloc(10,sizeof(int));//开辟了40个字节,并赋值为0
 3   if(pl==NULL){
 4     return 5   }
 6   for(int i=0;i<10;i++){
 7     pl[i]=i+1 8   }
 9   for(int i=0;i<10;i++){
10     printf("%d",pl[i]);
11   }
12   printf("\n");
    if(p1 != NULL)
    {
      free(p1);
      p1 = NULL;
    } 13    14 } 15 16 void test02(){ 17   int* pl=calloc(10,sizeof(int));//开辟了40个字节,并赋值为0 18   if(pl==NULL){ 19     return20   } 21   for(int i=0;i<10;i++){ 22     pl[i]=i+123   } 24   //申请空间,如果较小,后边增加返回的p2等于p1如果扩展比较大,重新申请(p2不等于p1),且把之前的数据拷贝至新分配的空间 25   int* p2=realloc(pl,15* sizeof(int)); 26   if(p2==NULL){ 27     return28   } 29   printf("%d\n",pl); 30   printf("%d\n",p2); 31 32   //打印 33   for(int i=0;i<15;i++){ 34     printf("%d",p2[i]); 35   } 36   printf("\n"); 37 38   //重新赋值 39   for(int i=0;i<15;i++){ 40     p2[i]=i+1; 41   } 42 43   //再次打印 44   for(int i=0;i<15;i++){ 45     printf("%d",p2[i]); 46   printf("\n"); 47   free(p2); 48 }

说明:calloc、realloc和sprintf类似,都是申请空间放入数据,sprintf把格式化后的结果放在显示器,calloc、realloc放在内存。

2、sscanf

 1 #include<stdio.h>
 2 int sscanf(const char *str,const char *format,...);
 3 功能:
 4     从str指定的字符串读取数据,并根据参数format字符串来转换并格式化数据。
 5 参数:
 6     str:指定的字符串首地址
 7     format:字符串格式,用法和scanf()一样
 8 返回值:
 9     成功:实际读取的字符个数
10     失败:-1

 练习:

 1 #define _CRT_SECURE_NO_WARNINGS
 2 #include<stdio.h>
 3 #include<string.h>
 4 #include<stdlib.h>
 5 
 6 //%*s或%*d 跳过数据
 7 void test01()
 8 {
 9 #if 0
10     char* str = "12345abcde";
11     char buf[1024] = { 0 };
12     sscanf(str, "%*d%s", buf);//跳过数字,剩余字符串
13     printf("buf:%s\n", buf);
14 #else
15     //忽略字符串到空格或者\t
16     char* str = "12345\tabcde";
17     char buf[1024] = { 0 };
18     sscanf(str, "%*s%s", buf);//跳过数字,剩余字符串
19     printf("buf:%s\n", buf);
20 #endif    
21     
22 }
23 
24 //%[width]s读指定宽度的数据
25 void test02()
26 {
27     char* str = "12345abcde";
28     char buf[1024] = { 0 };
29     sscanf(str, "%6s", buf);//指定6个字符,12345a
30     printf("buf:%s\n", buf);
31 }
32 //%[a-z]匹配a到z中任意字符(尽可能多的匹配)
33 void test03()
34 {
35     char* str = "12345abcde";
36     char buf[1024] = { 0 };
37     sscanf(str, "%*d%[a-c]", buf);//%[a-c]从第一个开始匹配,有不匹配的,直接结束,所以加入忽略数字
38     printf("buf:%s\n", buf);
39 }
40 //%[aBc]匹配a、B、c中一员,贪婪性
41 void test04()
42 {
43     char* str = "aABbcde";
44     char buf[1024] = { 0 };
45     sscanf(str, %[aAb]", buf);//%[Ab]从第一个开始匹配,有不匹配的,直接结束,所以为aA
46     printf("buf:%s\n", buf);
47 }
48 //%[^a]匹配非a的任意字符,贪婪性
49 void test05()
50 {
51     char* str = "aABbcde";
52     char buf[1024] = { 0 };
53     sscanf(str, %[^c]", buf);//%[^c]从第一个开始匹配,有不匹配的,直接结束,所以为aABb
54     printf("buf:%s\n", buf);
55 }
56 //%[^a-z]表示读取除a-z以外的所有字符
57 void test06()
58 {
59     char* str = "aABbcde12345";
60     char buf[1024] = { 0 };
61     sscanf(str, %[^a-z]", buf);//%[^a-z]从第一个开始匹配,有不匹配的,直接结束,所以为aABbcde
62     printf("buf:%s\n", buf);
63 }
64 //深入理解,分别提取IP各个字符
65 void test07()
66 {
67     char* ip = "127.0.0.1";
68     int num1 = 0, num2 = 2, num3 = 0, num4 = 0;
69     sscanf(ip, "%d.%d.%d.%d", &num1, &num2, &num3, &num4);
70     printf("num1:%d\n", num1);
71     printf("num2:%d\n", num2);
72     printf("num3:%d\n", num3);
73     printf("num4:%d\n", num4);
74 }
75 //深入理解,提取#和@中间的字符
76 void test08()
77 {
78     char* str = "abcde#12uiop@0plju";
79     char buf[1024] = {0};
80     sscanf(str, "%*[^#]#%[^@]", buf);
81     printf("buf:%s\n", buf);
82 }
83 
84 
85 int main(){
86 
87     test01();
88     
89     system("pause");
90     return EXIT_SUCCESS;
91 }

3、练习:查找子串

 

 1 #define _CRT_SECURE_NO_WARNINGS
 2 #include<stdio.h>
 3 #include<string.h>
 4 #include<stdlib.h>
 5 
 6 //查找子串第一次出现的位置
 7 char* myStrStr(const char* str, const char* substr)
 8 {
 9     const char* mystr = str;
10     const char* mysub = substr;
11     
12     while(*mystr != '\0')
13     {
14         if(*mystr != *mysub)
15         {
16             ++mystr;
17             continue;//找到相同的首个字符,才执行下边的比较
18         }
19         //临时指针变量
20         const char* temp_mystr = mystr;
21         const char* temp_mysub = mysub;
22         //比较子串
23         while(*temp_mysub != '\0')
24         {
25             if(*temp_mystr != *temp_mysub)
26             {
27                 ++mystr;
28                 break;//如果不匹配,退出本次比较(退出本层while),mystr加1开始下轮比较
29             }
30             ++temp_mysub;
31             ++temp_mystr;
32         }
33         //说明匹配成功
34         if(*temp_mysub == '\0')
35         {
36             return (char*)mystr;
37         }
38         
39         
40     }
41 }
42 
43 void test()
44 {
45     char* str = "abcdefg";
46     char* sub = "de";
47     char* pos = myStrStr(str, sub);
48     printf("pos = %s\n", pos);
49 }
50 
51 int main(){
52 
53     test();
54     
55     system("pause");
56     return EXIT_SUCCESS;
57 }

实现了查找子串,但还未实现删除后拼接。

C break——参看:https://www.runoob.com/cprogramming/c-break-statement.html

 

4、一级指针易错点
(1)越界

1 void test(){
2     char buf[3]="abc"; //有问题,'\0'还有一个字节
3     printf("buf:%s\n",buf);
4 }

(2)指针叠加会不断改变指针指向

 1 void test(){
 2     char* p=(char*)malloc(50);
 3     char buf[]="abcdef";
 4     int n=strlen(buf);
 5     int i=0;
 6 
 7     for(i=0;i<n;i++)
 8     {
 9         *p=buf[i];
10         p++;//修改原指针指向,修改原指针的首地址!free会出问题
11     }
12     free(p);
13 }

(3)返回局部变量地址

1 char *get_str()
2 {
3     char str[]="abcdedsgads"//栈区,子函数运行完,就释放,不能返回!
4     printf("[get_str]str=%s\n",str);
5     return str;
6 }

(4)同一块内存释放多次

 1 void test(){
 2     char* p=NULL;
 3     p=(char*)malloc(50);
 4     strcpy(p,"abcdef");
 5     if(p!=NULL)
 6     {
 7         //free()函数的功能只是告诉系统p指向的内存可以回收了
 8         //就是说,p指向的内存使用权交还给系统
 9         //但是,p的值还是原来的值(野指针),p还是指向原来的内存
10         free(p):
11     }
12     if(p!=NULL)
13     {
14         free(p):
15     }
16 }

 

 5、const使用

 1 #define _CRT_SECURE_NO_WARNINGS
 2 #include<stdio.h>
 3 #include<string.h>
 4 #include<stdlib.h>
 5 
 6 struct Person
 7 {
 8     char name[64];
 9     int age;
10     int ID;
11     double score;
12 };
13 
14 void PrintPerson(struct Person person)
15 {
16     printf("Name:%s Age:%d ID:%d Score:%f\n",person.name, person.age, person.ID, person.score);
17 }
18 
19 void test()
20 {
21     struct Person person = {"Trump", 30, 250, 59.9};
22     PrintPerson(person);
23 }
24 
25 int main(){
26 
27     test();
28     
29     system("pause");
30     return EXIT_SUCCESS;
31 }

代码分析:每次打印时候(调用PrintPerson函数)都要拷贝64+4+4+8=80个字节,特别浪费内存。所以考虑使用指针,然而只需要打印,为避免更改数据,使用const。

改进代码如下:

 1 #define _CRT_SECURE_NO_WARNINGS
 2 #include<stdio.h>
 3 #include<string.h>
 4 #include<stdlib.h>
 5 
 6 struct Person
 7 {
 8     char name[64];
 9     int age;
10     int ID;
11     double score;
12 };
13 
14 //规避地址传递的副作用(在使用对象指针的情况下,有可能意外修改数据)
15 void PrintPerson(const struct Person* person)
16 {
17     //person->ID = 128;//增加const后不可修改,修改会报错
18     printf("Name:%s Age:%d ID:%d Score:%f\n",person->name, person->age, person->ID, person->score);
19 }
20 
21 void test()
22 {
23     struct Person person = {"Trump", 30, 250, 59.9};
24     PrintPerson(&person);
25 }
26 
27 int main(){
28 
29     test();
30     
31     system("pause");
32     return EXIT_SUCCESS;
33 }

 

6、指针的指针(二级指针)

(1)二级指针基本概念

1 int a = 12;
2 int *b = &a;

假定我们又有了第3个变量,名叫c,并用下面这条语句对它

1 c = &b;

问题是:c的类型是什么?显然它是一个指针,但它所指向的是什么?变量b是一个“指向整型的指针”,所以任何指向b的类型必须是指向“指向整型的指针"的指针,更通俗地说,是一个指针的指针。

它合法吗?是的!指针变量和其他变量一样,占据内存中某个特定的位置,所以用&操作符取得它的地址是合法的。

那么这个变量的声明是怎样的声明的呢?

1 int **c=&b;

那么这个**c如何理解呢?*操作符具有从右向左的结合性,所以这个表达式相当于*(*c),我们从里向外逐层求值。*c访问c所指向的位置,我们知道这是变量b.第二个间接访问操作符访问这个位置所指向的地址,也就是变量a。指针的指针并不难懂,只需要留心所有箭头,如果表达式中出现了间接访问操作符,你就要随箭头访问它所指向的位置。

 

(2)二级指针做形参输出特性

二级指针做形参输出特性指由被调函数分配内存。

 1 #define _CRT_SECURE_NO_WARNINGS
 2 #include<stdio.h>
 3 #include<string.h>
 4 #include<stdlib.h>
 5 
 6 //被调函数分配内存,主调函数使用
 7 void allocateSpace(int** temp)//使用二级指针的目的是为了修改一级指针的值
 8 {
 9     int* arr = malloc(sizeof(int)* 10);
10     for(int i = 0; i < 10; ++i)
11     {
12         arr[i] = i + 1;
13     }
14     //指针间接赋值
15     *temp = arr;
16 }
17 
18 void printArray(int* arr, int len)
19 {
20     for(i = 0; i < len; ++i)
21     {
22         printf("%d", arr[i]);
23     }
24 }
25 #if 0
26 void freeSpace(void* arr)
27 {
28     if(arr == NULL)
29     {
30         return;
31     }
32     free(arr);
33     arr = NULL;
34 }
35 #else
36 void freeSpace(int** arr)
37 {
38     if(arr == NULL)
39     {
40         return;
41     }
42     if(*arr != NULL)
43     {
44         free(*arr);
45         *arr = NULL;
46         arr = NULL;
47     }
48 }
49 #endif
50 
51 void test()
52 {
53     int* pArray = NULL;
54     allocateSpace(&pArray);//本来一级,取完地址二级
55     printArray(pArray, 10);//pArray为int*类型,&pArray为int**类型
56 #if 0
57     freeSpace(pArray);
58     pArray = NULL;
59 #esle
60     freeSpace(&pArray);
61     if(pArray == NULL)
62     {
63         printf("pArray被置空!");
64     }
65 #endif
66 }
67 
68 int main(){
69 
70     test();
71     
72     system("pause");
73     return EXIT_SUCCESS;
74 }

 (3)二级指针做形参输入特性

二级指针做形参输入特性指由主调函数分配内存。

练习1:堆上开辟空间,指向栈上的空间

内存模型图如下:

 

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

void printArray(int **arr,int len)
{
    for (int i = 0; i < len; ++i)
    {
        printf("%d ",*arr[i]);
    }
}

void test01()
{

    //堆上分配指针数组
    int **pArray = malloc(sizeof(int *)* 6);

    //栈上分配数据空间
    int a1 = 100;
    int a2 = 200;
    int a3 = 300;
    int a4 = 400;
    int a5 = 500;
    int a6 = 600;

#if 0
    pArray[0] = &a1;
    pArray[1] = &a2;
    pArray[2] = &a3;
    pArray[3] = &a4;
    pArray[4] = &a5;
    pArray[5] = &a6;
#endif

    *(pArray + 0) = &a1;
    *(pArray + 1) = &a2;
    *(pArray + 2) = &a3;
    *(pArray + 3) = &a4;
    *(pArray + 4) = &a5;
    *(pArray + 5) = &a6;


    printArray(pArray, 6);

    //释放数组内存
    if (pArray != NULL)
    {
        free(pArray);
        pArray = NULL;
    }

}

int main(){

    test01();

    system("pause");
    return EXIT_SUCCESS;
}

练习2:栈上开辟空间,指向堆上的空间

内存模型图如下:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

void printArray(int **arr,int len)
{
    for (int i = 0; i < len; ++i)
    {
        printf("%d ",*arr[i]);
    }
}

void test01()
{

    //堆上分配指针数组
    int **pArray = malloc(sizeof(int *)* 6);

    //栈上分配数据空间
    int a1 = 100;
    int a2 = 200;
    int a3 = 300;
    int a4 = 400;
    int a5 = 500;
    int a6 = 600;

#if 0
    pArray[0] = &a1;
    pArray[1] = &a2;
    pArray[2] = &a3;
    pArray[3] = &a4;
    pArray[4] = &a5;
    pArray[5] = &a6;
#endif

    *(pArray + 0) = &a1;
    *(pArray + 1) = &a2;
    *(pArray + 2) = &a3;
    *(pArray + 3) = &a4;
    *(pArray + 4) = &a5;
    *(pArray + 5) = &a6;


    printArray(pArray, 6);

    //释放数组内存
    if (pArray != NULL)
    {
        free(pArray);
        pArray = NULL;
    }

}

void test02()
{
    
    int* pArray[5];

    for (int i = 0; i < 5; ++i)
    {
        pArray[i] = malloc(4);
        *(pArray[i]) = 100 + i;
    }

    printArray(pArray, 5);

    //释放堆内存
    for (int i = 0; i < 5; ++i)
    {
        if (pArray[i] != NULL)
        {
            free(pArray[i]);
            pArray[i] = NULL;
        }
    }
}

int main(){

    //test01();
    test02();

    system("pause");
    return EXIT_SUCCESS;
}

 

(4)二级指针练习

读取文件(text.txt)内容

 

1 //text.txt
2 aaaaaaaaaaaaaaaaaa
3 bbbbbbbbbbbbbbbbbbbbbbbbbb
4 cccccccccccc
5 ddd
6 eeeeeeeeeeeeeeeee
7 ffffffffffffffffffffffffffff

内存模型图如下:

 

  1 #define _CRT_SECURE_NO_WARNINGS
  2 #include<stdio.h>
  3 #include<string.h>
  4 #include<stdlib.h>
  5 
  6 //获得文件行数
  7 int getFileLines(FILE* file)
  8 {
  9     if(NULL == file)
 10     {
 11         return -1;
 12     }
 13     char buf[1024] = {0};
 14     int lines = 0;
 15     
 16     while(fgets(buf, 1024, file)!=NULL)
 17     {
 18         ++lines;
 19     }
 20     //恢复文件指针指向文件起始位置
 21     fseek(file, 0, SEEK_SET);
 22         
 23     return lines;
 24 }
 25 
 26 //读取文件数据
 27 void readFileData(FILE* file, int lines, char** contents)
 28 {
 29     if(NULL == file)
 30     {
 31         return;
 32     }
 33     if(NULL == contents)
 34     {
 35         return;
 36     }
 37     if(lines <= 0)
 38     {
 39         return;
 40     }
 41     //创建缓冲区
 42     char buf[1024] = {0};
 43     int index = 0;
 44     while(fgets(buf, 1024, file) != NULL)
 45     {
 46         //printf("buf:%s",buf);
 47         int curLineLen = strlen(buf) + 1;//strlen计算给定字符串的(unsigned int型)长度,不包括'\0'在内
 48         //给当前行分配内存
 49         char* lineContent = malloc(sizeof(char) * curLineLen);
 50         //将行数据拷贝到空间中
 51         strcpy(lineContent, buf);
 52         contents[index++] = lineContent;
 53         memset(buf,0,1024);
 54     }
 55     
 56     
 57     
 58 }
 59 //打印文件内容
 60 void showFileContents(char** contents, int lines)
 61 {
 62     for(int i = 0; i < lines; ++i)
 63     {
 64         printf("%d行:%s",i+1,contents[i]);
 65     }
 66 }
 67 
 68 //释放文件数据内存
 69 void freeFileSpace(char** contents, int lines)
 70 {
 71     for(int i = 0; i < lines; ++i)
 72     {
 73         if(contents[i] != NULL)
 74         {
 75             free(contents[i]);
 76             contents[i] = NULL;
 77         }
 78     }
 79     free(contents);
 80     contents = NULL;
 81 }
 82 
 83 void test()
 84 {
 85     //打开文件
 86     FILE* file = fopen("./text.txt","r");
 87     if(NULL == file)
 88     {
 89         printf("打开文件失败!\n");
 90         return;
 91     }
 92     //统计文件行数
 93     int lines = 10;
 94     lines = getFileLines(file);
 95     printf("lines:%d\n",lines);
 96     
 97     char** pContents = malloc(sizeof(char*) * lines);
 98     
 99     //读取文件内容
100     readFileData(file, lines, pContents);
101     
102     //关闭文件
103     fclose(file);
104     file = NULL;
105     
106     //打印文件内容
107     showFileContents(pContents, lines);
108     
109     //释放文件数据
110     freeFileSpace(pContents, lines);
111     
112 }
113 
114 int main(){
115 
116     test();
117     
118     system("pause");
119     return EXIT_SUCCESS;
120 }

 

7、位运算

可以使用C对变量中的个别位进行操作。您可能对人们想这样做的原因感到奇怪。这种能力有时确实是必须的,或者至少是有用的。C提供位的逻辑运算符和移位运算符。在以下例子中,我们将使用二进制计数法写出值,以便您可以了解对位发生的操作。在一个实际程序中,您可以使用一般的形式的整数变量或常量。例如不适用00011001的形式,而写为25或者031或者0x19.在我们的例子中,我们将使用8位数字,从左到右,每位的编号是7到0。

(1)位逻辑运算符

4个位运算符用于整型数据,包括char。将这些位运算符成为位运算的原因是它们对每位进行操作,而不影响左右两侧的位。请不要将这些运算符与常规的逻辑运算符(&&、||和!)相混淆,常规的位的逻辑运算符对整个值进行操作。

1)按位取反~
一元运算符~将每个1变为0,将每个0变为1,如下面的例子:

1 ~(10011010)
2 01100101

假设a是一个unsigned char,已赋值为2.在二进制中,2是00000010.于是~a的值为11111101或者253。请注意该运算符不会改变a的值,a仍为2。

unsigned char a=2;//00000010
unsigned char b=~a;//11111101
printf("ret=8d\n",a);//ret=2
printf("ret=%d\n",b);//ret=253

带符号整型的需要注意:int number =2; ~a得到101,而负数采用补码存储,得到-3


2)位与(AND):&
二进制运算符&通过对两个操作数逐位进行比较产生一个新值。对于每个位,只有两个操作数的对应位都是1时结果才为1。

1100100112 &(00111101)
3 =(00010001

C也有一个组合的位与-赋值运算符:&=。下面两个将产生相同的效果:

1 val&=0377
2 val=val & 0377

可判断一个数的奇偶性——思路:取出最后一位:(number&1)==0为偶数,否则为奇数

应用:取出某一位;把某一位清零


3)位或(OR):|
二进制运算符通过对两个操作数逐位进行比较产生一个新值。对于每个位,如果其中任意操作数中对应的位为1,那么结果位就为1.

110010011)
2 |(00111101)
3 =(10111111

C也有组合位或赋值运算符:|=

1 val |=0377
2 val=val | 0377

应用:把某一位置1

4)位异或:^
二进制运算符对两个操作数逐位进行比较。对于每个位,如果操作数中的对应位有一个是1(但不是都是1),那么结果是1.如果都是0或者都是1,则结果位0.——类似于做差取绝对值!

1100100112 ^(001111013 =(10101110

C也有一个组合的位异或-赋值运算符:^=

1 val^=0377
2 val=val ^ 0377

应用:不需要第三个变量,可交换两个变量。

 

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//1. 按位取反 ~
void test01()
{
    int number = 2; //010   101  负数使用补码存储 110 + 1 ,111  -3
    printf("~number : %d\n", ~number);
}

//2. 位与 &
void test02()
{
    int number = 332;
    if ((number & 1) == 0)
    {
        printf("%d是偶数!\n",number);
    }
    else
    {
        printf("%d是奇数!\n",number);
    }

    //number = number & 0;
    number &= 0;
    printf("number:%d\n", number);
}

//3. 位或 |
void test03()
{
    int num1 = 5;
    int num2 = 3;

    printf("num1 | num2 = %d\n", num1 | num2);
}

//4 位抑或 ^
void test04()
{
    int num1 = 5;
    int num2 = 9;

#if 0
    int temp = num1;
    num1 = num2;
    num2 = temp;
#endif

    printf("num1:%d num2:%d\n", num1, num2);

    num1 = num1 ^ num2;
    num2 = num1 ^ num2;
    num1 = num1 ^ num2;


    //num1 = num1 ^ num2;
    //num2 = num1 ^ num2;
    //num1 = num1 ^ num2;

    printf("num1:%d num2:%d\n",num1,num2);

}

//左移运算符 左移几位就相当于乘以2的几次方
void test05()
{
    int number = 20;
    printf("number = %d\n" , number <<= 2);
    printf("number = %d\n", number >>= 1);
}



int main(){

    //test01();
    //test02();
    //test03();
    //test04();
    test05();

    system("pause");
    return EXIT_SUCCESS;
}

 

(2)移位运算符
现在让我们了解一下C的移位运算符。移位运算符将位向左或向右移动。同样,我们仍将明确地使用二进制形式来说明该机制的工作原理。

1)左移<<
左移运算符<<将其左侧操作数的值的每位向左移动,移动的位数由其右侧操作数指定。空出来的位用0填充,并且丢弃移出左侧操作数未端的位。在下面例子中,每位向左移动两个位置。

1 (10001010)<<2
200101000

该操作将产生一个新位置,但是不改变其操作数。

1 1<<1=22 2<<1=43 4<<1=84 8<<2=32;

左移一位相当于原值*2。

2)右移
右移运算符>>将其左侧的操作数的值每位向右移动,移动的位数由其右侧的操作数指定。丢弃移出左侧操作数有段的位。对于unsigned类型,使用0填充左端空出的位。对于有符号类型,结果依赖于机器。空出的位可能用0填充,或者使用符号(最左端)位的副本填充。

 1 //有符号值
 2 (10001010)>>2
 3 (00100010)//在某些系统上的结果值
 4 
 5 (10001010)>>2
 6 (11100010)//在另一些系统上的结果
 7 
 8 //无符号值
 910001010)>>2
1000100010//所有系统上的结果值

 

3)用法:移位运算符
移位运算符能够提供快捷、高效(依赖于硬件)对2的幂的乘法和除法。

 

 

参考:

1)讲义:豆丁网:https://www.docin.com/p-2159552288.html
道客巴巴:https://www.doc88.com/p-6951788232280.html

2)C break——参看:https://www.runoob.com/cprogramming/c-break-statement.html

 

在学习c语言提高总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

posted on 2020-06-05 19:40  Alliswell_WP  阅读(188)  评论(0编辑  收藏  举报

导航