C语言学习笔记

简介: C语言学习笔记
//一个8位的空间,如果表示无符号数0-255 unsigned char  0~2^8 -1
//如果用来表示有符号数 -128~127       char           -2^7 ~2^7-1
//对其范围的探求,不止于,自字节数
#if 0
1字节 char
0 - 255 unsigned char         0~2^8 - 1
-128~127         char           -2^7 ~2^7-1

2字节 short
0    -65535                    0 ~2^16 -1
-32768 -32767                  -2^15~ 2^15-1

4个字节 int
#endif

输入输出

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
   
    
    int a = 1;
    printf("%2d\n", 123456);//当实际宽度大于域宽时,按实际输出
    printf("%2d\n", a);
    printf("%10d\n", 10);
    printf("%-10d###\n", 10); //左对齐
    printf("%15d\n", 123456); //默认空格 
    printf("%015d\n", 123456); //0 右对齐时用0补齐  默认空格
}
/*
123456
 1
        10
10        ###
         123456
000000000123456
*/

数组

//相同的数据类型构造,就构成了数组
//不同的数据类型,就构成了结构体

//对于构造类型来说,
//定义 大小 初始化 访问

//未初始化
//满初始化
//部分初始化,其余部分清零;初始化清零
//越界初始化 禁止 c语言对于越界是不检的 灵活

凡是构造类型,在定义的时候初始化,不可以先定义再初始化的方式赋值

凡是基本数据类型,既可以在定义时初始化,也可以先定义,再赋值

int main(int argc, char* argv[]) {
   
   
    int arr[10] = {
   
    1,2,3,4,5,6,7,8,9,10};
    for (int i = 0; i < 10; i++) {
   
   
        printf("arr[%d] = %d\n",i,arr[i]);
    }
    printf("sizeof(arr)=%d\n", sizeof(arr));
    printf("sizeof(arr[0])=%d", sizeof(arr[0]));
}
int main(int argc, char* argv[]) {
   
   
    int arr[10] = {
   
   0};
    for (int i = 0; i < 10; i++) {
   
   
        arr[i] = rand() % 50; //[0,50)
    }
    for (int i = 0; i < 10;i++) {
   
   
        printf("arr[%d] = %d\n",i,arr[i]);
    }
}

一维数组的存储

一维数组,在内存中是一段连续的存储区域

#include <stdio.h>


int main(int argc, char* argv[]) {
   
   
    int arr[10];
    for (int i = 0; i < 10; i++) {
   
   
        printf("&arr[%d]= %p\n",i,&arr[i]);
    }
}
/*
&arr[0]= 000000231DF2FCC8
&arr[1]= 000000231DF2FCCC
&arr[2]= 000000231DF2FCD0
&arr[3]= 000000231DF2FCD4
&arr[4]= 000000231DF2FCD8
&arr[5]= 000000231DF2FCDC
&arr[6]= 000000231DF2FCE0
&arr[7]= 000000231DF2FCE4
&arr[8]= 000000231DF2FCE8
&arr[9]= 000000231DF2FCEC
*/

数组的三要素

数组的声明,已经把数组访问不的三要素,均已表示出来了,三要素就是,起始位置、移步刻度、终止位置。

#include <stdio.h>


int main(int argc, char* argv[]) {
   
   
    int maxValue;
    int minValue;
    int arr[10] = {
   
   100,2,7,4,5,6,7,8,9,10};
    maxValue = arr[0];
    minValue = arr[0];
    for (int i = 0; i < 10; i++) {
   
   

        if (maxValue < arr[i]) {
   
   
            maxValue = arr[i];
        }
        if (minValue > arr[i]) {
   
   
            minValue = arr[i];
        }
    }
    printf("int arr max = %d;min = %d", maxValue, minValue);
    return 0;
}
#include <stdio.h>
int main(void)
{
   
   
//    int arr[] = { 1,2,3,4,56 };
//    int[4] arr[3];
//    int arr[3][4]; // int[4] arr[3];T arr[3]
    int arr[][3] = {
   
    1,2,4,5,6,7,9,10,11,12 };
    for (int i = 0; i < sizeof(arr) / sizeof(int[3]); i++) {
   
   
        for (int j = 0; j < 3; j++) {
   
   
            printf("%3d", arr[i][j]);
        }
        putchar(10);
    }
    printf("sizeof(arr)=%d\n",sizeof(arr));
    return 0;
}

三要素

#include <stdio.h>
int main(void)
{
   
   
    int arr[4];
    printf("%p\n", arr); //起始地址
    printf("&arr[0] = %p\n", &arr[0]);
    printf("arr = %p arr + 1 = %p\n",arr,arr + 1); //步长

    return 0;
}
#include <stdio.h>
int main()
{
   
   
    int arr[3][4]; //int[4] arr[3]  T arr[3]

    printf("arr =  %p \n", arr); //起始地址
    printf("&arr[0] = %p\n", &arr[0]);
    printf("arr = %p arr + 1 = %p\n", arr, arr + 1); //步长 16 一个一维数组的大小

    printf("arr[0] = %p\n",arr[0]); //内嵌一维数组的起始地址
    printf("&arr[0][0] =%p \n",& arr[0][0]); //内嵌一维数组首元素的地址
    printf("arr[0] + 1 = %p\n",arr[0] + 1);//内嵌一维数组的步长 4 

    printf("sizeof(arr[0]) = %d sizeof(int[4])= %d\n",sizeof(arr[0]), sizeof(int[4])); //16
    printf("sizeof(arr) = %d\n", sizeof(arr)); //48
        for (int i = 0; i < 3; i++) {
   
   
        for (int j = 0; j < 4; j++) {
   
   
            arr[i][j] = rand() % 100;
    }
    }
    for (int i = 0; i < 3; i++) {
   
   
        for (int j = 0; j < 4; j++) {
   
   
            printf("%3d", arr[i][j]);
        }
        putchar(10);
    }
    return 0;
}
/*
arr =  000000869E33FBB8
&arr[0] = 000000869E33FBB8
arr = 000000869E33FBB8 arr + 1 = 000000869E33FBC8
arr[0] = 000000869E33FBB8
&arr[0][0] =000000869E33FBB8
arr[0] + 1 = 000000869E33FBBC
sizeof(arr[0]) = 16 sizeof(int[4])= 16
sizeof(arr) = 48
 41 67 34  0
 69 24 78 58
 62 64  5 45
*/

//一维数组的数组名,是一级指针

//二维数组的数组名是,数组指针

arr = &arr[0]
*arr = arr[0]
#include <stdio.h>
int main()
{
   
   
    int arr[3][4];
    printf("arr = %p\n", arr);
    printf("&arr[0] = %p\n", &arr[0]);
    printf("arr+1 = %p\n", arr + 1);
    // & reference * dereferrence
    printf("arr[0] = %p\n",arr[0]);
    printf("&arr[0][0] = %p\n", &arr[0][0]);
    printf("arr[0] + 1 = %p\n", arr[0] + 1);

    printf("arr = %p\n", arr );
    printf("arr + 1= %p\n", arr + 1);
    //arr = &arr[0]
    printf("*arr = %p\n", *arr);//arr[0]
    printf("*arr + 1 = %p\n", *arr + 1);
    return 0;
}
/*
arr = 000000B6EE10FC28
&arr[0] = 000000B6EE10FC28
arr+1 = 000000B6EE10FC38
arr[0] = 000000B6EE10FC28
&arr[0][0] = 000000B6EE10FC28
arr[0] + 1 = 000000B6EE10FC2C
arr = 000000B6EE10FC28
arr + 1= 000000B6EE10FC38
*arr = 000000B6EE10FC28
*arr + 1 = 000000B6EE10FC2C
*/

二维数组的数组名是,数组指针

#include <stdio.h>
int main()
{
   
   
    int arr[3][4] = {
   
    {
   
   2,2,2,0} ,{
   
   1,2,0,3}, {
   
   4,4,4,4} };
    printf("arr = %p\n", arr);
    printf("&arr[0] = %p\n", &arr[0]);
    printf("arr+1 = %p\n", arr + 1);
    // & reference * dereferrence
    printf("arr[0] = %p\n",arr[0]);
    printf("&arr[0][0] = %p\n", &arr[0][0]);
    printf("arr[0] + 1 = %p\n", arr[0] + 1);

    printf("arr = %p\n", arr );
    printf("arr + 1= %p\n", arr + 1);
    //arr = &arr[0]
    printf("*arr = %p\n", *arr);//arr[0]
    printf("*arr + 1 = %p\n", *arr + 1);

    //想访问第2行的第二个元素  arr+1 => a[1]  *(arr + 1) = &a[1]   
//(*(arr + 1) + 1) => &a[1][1]
    printf("a[1][1] = %d\n", *(*(arr + 1) + 1));
                                 //&arr[0] + 1  =  &a[1] =
    //想访问第2行的第二个元素  arr+1 => &a[1]  *(arr + 1) = &a[1]   
//(*(arr + 1) + 1) => &a[1][1] 
    return 0;
}
/*
arr = 000000CC63CFF518
&arr[0] = 000000CC63CFF518
arr+1 = 000000CC63CFF528
arr[0] = 000000CC63CFF518
&arr[0][0] = 000000CC63CFF518
arr[0] + 1 = 000000CC63CFF51C
arr = 000000CC63CFF518
arr + 1= 000000CC63CFF528
*arr = 000000CC63CFF518
*arr + 1 = 000000CC63CFF51C
a[1][1] = 2
*/
int main() {
   
   
    char *p, q;//声明了一个指针变量,一个int类型的变量
    printf("sizeof(p) = %d sizeof(q) = %d\n",sizeof(p),sizeof (q));

}

指针的运算

#include <stdio.h>
//指针 类型(步长) 地址(物理数据)
int main() {
   
   
    int data = 0x12345678;
    char *pc = &data;
    printf("%x\n", *pc);
    int *p = (int *) 0x0001;
    int pData = 0x0001;
    printf("p = %#x  p+1 = %#x\n", p, p + 1);
    printf("pData = %#x  pData+1 = %#x\n", pData, pData + 1);

    printf("(double*)p = %#x  (double*)p+1 = %#x\n", (double*)p, (double*)p + 1);
    printf("(int)pData = %#x  (int)pData+1 = %#x\n", (int)pData, (int)pData + 1);

    printf("%x\n",++p);
    printf("%x\n",++pData);

    int arr[10];
    int pHead = (int)&arr[0];int pTail = (int)&arr[9];
    printf("%d\n",pHead - pTail); //-36
//    int arr[10];
//    int *pHead = &arr[0];int *pTail = &arr[9];
//    printf("%d\n",pHead - pTail); //-9
}
/*
pData = 0x1  pData+1 = 0x2
(double*)p = 0x1  (double*)p+1 = 0x9
(int)pData = 0x1  (int)pData+1 = 0x2
5
2
-36
*/

判断是否是回文数

int main() {
    
    
 char name[5] = {
    
    'm', 'a', 'd', 'a', 'm'};
 char *ph = &name[0];
 char *pt = &name[4];
 int flag = 1;
 while(ph < pt){
    
    
     if (*ph == *pt ){
    
    
         ph ++;
         pt --;
     }
     else{
    
    
         break;
         flag = 0;
     }
 }
 if (flag == 1){
    
    
     printf("yes");
 }
 else{
    
    
     printf("非回文");
 }
 return 0;
}
#include <stdio.h>
int main() {
   
   
//数组访问  偏移法
    int arr[10] = {
   
   1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
//    for (int i = 0; i < 10; i++) {
   
   
//        printf("%d\n", *(arr + i)); // arr = &arr[0]   *arr = arr[0]
//    }
    //数组名是指针常量,方可唯一的表示一个数组。数组名是数组的唯一标识符。
    printf("arr = %p\n", arr);
    printf("arr + 1 = %p\n", arr + 1);

    printf("&arr[0] = %p\n", &arr[0]);
    printf("&arr[0]+1=%p", &arr[0] + 1);
    //&arr[0] ==arr 在一定程度上。 int *
    //一维数组名,可以赋给一级指针
    int *pa = &arr[0];
    int *pb = arr;
    //数组名能干的指针就能干,数组名不能干的 指针也能干
    return 0;
}
/*
arr = 00000073a7dff970
arr + 1 = 00000073a7dff974
&arr[0] = 00000073a7dff970
&arr[0]+1=00000073a7dff974
*/
#include <stdio.h>
int main() {
   
   
    int arr[10] = {
   
   1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int *pa = arr;
    for (int i = 0; i < 10; i++) {
   
   
        printf("%d\n", *(pa + i));
    }
    for (int i = 0; i < 10; i++) {
   
   
        printf("%d\n", pa[i]);
    }
    for (int i = 0; i <10 ; ++i) {
   
   
        printf("%d\n",*pa++);
    }
    return 0;
}
int *pa = arr;
for (int i = 0; i < 10; ++i) {
    
    
 printf("%d\n", *(pa++));
}

小结:

  1. 数组名是一个常量,不允许重新赋值
  2. 指针变量是一个变量,可以重新赋值
  3. p+i和a+i均表示数组元素a[i]的地址,均指向a[i]
  4. //(p+i)和 (a+i)均表示p+i和a+i所指向的内容a[i]
  5. p++ = (p++) 先得到 *p 再使 p=p+1
  6. (*p)++表示将p所指向的元素的值加一,等价于a[i]++
  7. 指向数组元素的指针也可以表示成数组的形式,即允许指针变量带下标,*(p+i) 也可以表示成p[i]

二维数组的访问方式

下标法

​ 数组元素的表示方法是:数组名[行] [列]

本质偏移法

​ a a[0] a[0] [0]

int a[3] [4]; a = &a[0]

*a = a[0]

&a[0] = a

a[i] <==> *(a+i)

a[i] [j] <==> ((a+i)+j)

a是数组首元素的地址,所以a的值和&a[0]的值相同,另一方面,a[0]本身是包含4个整数的数组,因此,a[0]的值同其首元素的地址&a[0] [0]相同。简单的讲,a[0]是一个整数大小对象的地址,而a是4个整数大小对象的地址。因为整数和4个整数组成的数组开始于同一个地址,因此a和a[0]的值是相同的。

a 所指的对象大小是4个int,而a[0]所指的对象大小一个int 所以a+1 和 a[0] + 1

推论(仅助理解)

二维数组名解引用,降维为一维数组名 *(a+1) a[1]

一维数组名,对其引用,升级为二维数组名 &a[1] <>(a+1)

&引用和*解引用互为逆向关系

#include <stdio.h>
int main() {
   
   
    int arr[3][4] = {
   
   1, 2, 3, 4,
                     10, 20, 30, 40,
                     100, 200, 300, 400};
    for (int i = 2; i >= 0; i--) {
   
   
        for (int j = 3; j >= 0; j--) {
   
   
            printf("arr[%d][%d] = %#x\n", i, j, &arr[i][j]);
        }
        printf("=======\n");
    }
    // arr[2][1]  ==> *(*(arr + 2)+1)
    printf("%d\n", *(*(arr + 2) + 1));
    printf("arr = %#p arr+1 = %#x arr+2 = %#x \n", arr, arr + 1, arr + 2);
    printf("arr[0] = %#p arr[0]+1 = %#x arr[0]+2 = %#x \n", arr[0], arr[0] + 1, arr[0] + 2);
    printf("*arr = %#p *arr+1 = %#x *arr+2 = %#x \n", *arr, *arr + 1, *arr + 2);
    printf("&arr[0] = %#p &arr[0]+1 = %#x &arr[0]+2 = %#x \n", &arr[0], &arr[0] + 1, &arr[0] + 2);

    printf("arr[0][0] = %d arr[0][1] = %d arr[0][2] = %d \n", *arr[0], *(arr[0] + 1), *(arr[0] + 2));
    printf("arr[0][0] = %d arr[0][1] = %d arr[0][2] = %d \n", **arr, *(*arr + 1), *(*arr + 2));

    //arr   arr[0]
    // *arr  --> arr[0]
    //arr[0]  arr
    // &arr[0] --> arr
    return 0;
}
/*
arr[2][3] = 0x1e9ffa1c
arr[2][2] = 0x1e9ffa18
arr[2][1] = 0x1e9ffa14
arr[2][0] = 0x1e9ffa10
=======
arr[1][3] = 0x1e9ffa0c
arr[1][2] = 0x1e9ffa08
arr[1][1] = 0x1e9ffa04
arr[1][0] = 0x1e9ffa00
=======
arr[0][3] = 0x1e9ff9fc
arr[0][2] = 0x1e9ff9f8
arr[0][1] = 0x1e9ff9f4
arr[0][0] = 0x1e9ff9f0
=======
200
arr = 0x481e9ff9f0 arr+1 = 0x1e9ffa00 arr+2 = 0x1e9ffa10
arr[0] = 0x481e9ff9f0 arr[0]+1 = 0x1e9ff9f4 arr[0]+2 = 0x1e9ff9f8
*arr = 0x481e9ff9f0 *arr+1 = 0x1e9ff9f4 *arr+2 = 0x1e9ff9f8
&arr[0] = 0x481e9ff9f0 &arr[0]+1 = 0x1e9ffa00 &arr[0]+2 = 0x1e9ffa10
arr[0][0] = 1 arr[0][1] = 2 arr[0][2] = 3
arr[0][0] = 1 arr[0][1] = 2 arr[0][2] = 3

Process finished with exit code 0

*/

二维数组的本质是,数组指针 二维数组名 跟二级指针没有毛关系

#include <stdio.h>
int main()
{
   
   
    char* p = "abcdef";//"abcdef"是一个常量字符串
    //*p = 'W'; 错误的 segmentation fault 段错误
    printf("%s\n",p);
    printf("%c\n", *p);
    printf("%s\n",p); //%s 指针p 会打印整个字符串
    return 0;

}
int main()
{
   
   
    char arr1[] = "abcdef";
    char arr2[] = "acbdef";
    char* p1 = "abcdef";
    char* p2 = "abcdef";
    if (arr1 == arr2)
    {
   
   
        printf("hehe\n");
    }
    else
    {
   
   
        printf("haha\n");
    }
}
//输出haha
int main()
{
   
   
    char arr1[] = "abcdef";
    char arr2[] = "acbdef";
    char* p1 = "abcdef";
    char* p2 = "acbdef";
    if (p1 == p2)
    {
   
   
        printf("hehe\n");
    }
    else
    {
   
   
        printf("haha\n");
    }
}
//输出hehe

指针数组 是数组 用来存放指针的

int main()
{
   
   
    int arr[10] = {
   
    0 };//整型数组
    char ch[5] = {
   
    0 };//字符数组
    int* parr[4];//存放整型指针的数组 -指针数组
    char* pch[5];//存放字符指针的数组 -指针数组
    return 0;
}
int main()
{
   
   
    int a = 10;
    int b = 20;
    int c = 30;
    int d = 40;
    int* arr[4] = {
   
    &a,&b,&c,&d };
    int i = 0;
    for (i = 0; i < 4; i++)
    {
   
   
        printf("%d ",*(arr[i]));
    }
    return 0;
}
//输出 10 20 30 40

指针加一并不是单纯的加一,而是指向下一个元素的地址,看指针的类型,例如int 则是郏4个字节

int main()
{
   
   
    int arr1[] = {
   
   1,2,3,4,5};
    int arr2[] = {
   
   2,3,4,5,6};
    int arr3[] = {
   
   3,4,5,6,7};
    int* parr[] = {
   
   arr1, arr2,arr3};
    for (int i = 0; i < 3; i++)
    {
   
   
        for (int j = 0; j < 5; j++)
        {
   
   
            printf("%d ", * (parr[i] + j));
        }
        printf("\n");
    }
    return 0;
}

数组指针

//数组指针 - 指针
int main()
{
   
   
    //int* p = NULL;//整型指针 -指向整型的指针 - 可以存放整型的地址
    //char* pc = NULL;//pc是字符指针 -指向字符的指针 - 可以存放字符的地址
    //数组指针 - 指向数组的指针 - 可以存放数组的地址
    //int arr[10] = { 0 };
    // arr - 首元素地址
    //&arr[0]- 首元素地址
    //&arr - 数组的地址
    int arr[10] = {
   
    1,2,3,4,5,6,7,8,9,10 };
    int (*p)[] = &arr;//数组的地址要存起来
    printf("%d", (*p)[0]); //(*p) 相当于 arr
}
int main()
{
   
   
    char* arr[5];
    char* (*pa)[5] = &arr;
    return 0;
}

数组指针的使用

int main()
{
   
   
    int arr[10] = {
   
    1,2,3,4,5,6,7,8,9,10 };
    int (*pa)[10] = &arr;
    for (int i = 0; i < 10; i++)
    {
   
   
        //printf("%d ",(* pa)[i]);
        printf("%d ", *(*pa + i));// *pa数组首元素的地址 + i 第i个元素的地址  然后解引用
    }
    return 0;
}
//参数是数组的方式
void print1(int arr[3][5],int x,int y)
{
   
   
    for (int i = 0; i < 3; i++)
    {
   
   
        for (int j = 0; j < 5; j++)
        {
   
   
            //printf("%d ", (*(arr))[i] + j);
            printf("%d ", arr[i][j]); //理解成二维数组中 一维数组的 数组名
        }
        printf("\n");
    }
}
//参数是指针的形式
void print2(int (*p)[5],int x,int y)
{
   
   
    for (int i = 0; i < x; i++)
    {
   
   
        for (int j = 0; j < y; j++)
        {
   
   
            //printf("%d ", *(*(p + i) + j));
            printf("%d ", (*(p + i))[j]);
        }
        printf("\n");
    }
}
int main()
{
   
   
    int arr[3][5] = {
   
    {
   
   1,2,3,4,5},{
   
   2,3,4,5,6},{
   
   3,4,5,6,7} };
    print1(arr,3,5);//arr - 数组名 - 首元素地址  看成一维数组 就是{1,2,3,4,5}这个数组的地址
    print2(arr, 3, 5);
    return 0;
}
/*
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
*/
int arr[10] = {
    
     1,2,3,4,5,6,7,8,9,10 };
int i = 0;
int* p = arr;
for (int i = 0; i < 10; i++)
{
    
    
    printf("%d ", p[i]);
    //printf("%d ", *(p + i));
    //printf("%d ", *(arr + i));
    //printf("%d ", arr[i]);  //arr[i] == *(arr+i) == *(p+i) ==p[i]
}
return 0;

arr[i] == (arr+i) == (p+i) ==p[i]

改写

void print2(int (*p)[5],int x,int y)
{
   
   
    for (int i = 0; i < x; i++)
    {
   
   
        for (int j = 0; j < y; j++)
        {
   
   
            //printf("%d ", *(*(p + i) + j));
            //printf("%d ",*(p[i]+j))
            printf("%d ", p[i][j]);
            //printf("%d ", (*(p + i))[j]);        

        }
        printf("\n");
    }
}
int main()
{
   
   
    int arr[3][5] = {
   
    {
   
   1,2,3,4,5},{
   
   2,3,4,5,6},{
   
   3,4,5,6,7} };
    print2(arr, 3, 5);
    return 0;
}

指针Pointer

认识内存

线性内存

内存的最小单位b 内存的最小编址单元B,内存中每个字节都对应一个地址,通过地址才能找到每个字节。

#include <stdio.h>
int main(int argc, char* argv[]) {
   
   
    int arr[3][4] = {
   
    1,2,3 };
    for (int i = 0; i < 3; i++)
    {
   
   
        for (int j = 0; j < 4; j++) {
   
   
            printf("%p\n",&arr[i][j]);
        }
        putchar(10); //输出一个ascii码值是10的字符 即回车换行
    }
    return 0;
}
/*
00000050F78FF7F8
00000050F78FF7FC
00000050F78FF800
00000050F78FF804

00000050F78FF808
00000050F78FF80C
00000050F78FF810
00000050F78FF814

00000050F78FF818
00000050F78FF81C
00000050F78FF820
00000050F78FF824*/
#include <stdio.h>
int main(int argc, char* argv[]) {
   
   
    //除了char占一个字节,占一个地址
    // 其他类型包含多个字节,也就是拥有多个地址。
    //当我们变量取地址的时候 拿到的是哪个字节的地址? 低字节的地址
    char a; short b; int c; double d;
    printf("%p\n", &a); printf("%#x\n", &a);
    printf("%p\n", &b); printf("%#x\n", &b);
    printf("%p\n", &c); printf("%#x\n", &c);
    printf("%p\n", &d); printf("%#x\n", &d);

    printf("sizeof(a) = %d\n",sizeof(&a));
    printf("sizeof(b) = %d\n", sizeof(&b));
    printf("sizeof(c) = %d\n", sizeof(&c));
    printf("sizeof(d) = %d\n", sizeof(&d));
    return 0;
}
/*
000000A16E14F5D4
0x6e14f5d4
000000A16E14F5F4
0x6e14f5f4
000000A16E14F614
0x6e14f614
000000A16E14F638
0x6e14f638
sizeof(a) = 8
sizeof(b) = 8
sizeof(c) = 8
sizeof(d) = 8*/

指针常量

指针常量 ->指针变量

对变量取地址,取出的地址,就是一个指针,且常量指针

& * reference derefer 取地址 取内容

常量指针不是一个单纯的地址,而是有类型的

指针的本质,是一个有类型的地址,类型决定了,从这个地址开始的寻址能力。

#include <stdio.h>
int main(int argc, char* argv[]) {
   
   

    //指针常量 ->指针变量
    //对变量取地址,取出的地址,就是一个指针,且常量指针
    //& * reference derefer 取地址 取内容
    char a = 1; short b = 2; int c = 10; double d = 123.45;
    printf("%p ", &a); printf("%#x\n", &a);
    printf("%p ", &b); printf("%#x\n", &b);
    printf("%p ", &c); printf("%#x\n", &c);
    printf("%p ", &d); printf("%#x\n", &d);
    printf("%d\n",*(&a));
    printf("%d\n",*(&b));
    printf("%d\n",*(&c));
    printf("%f\n",*(&d));
    printf("%d\n", *((char*) 0x8a53fca4));
    printf("%d\n", *((short*) 0x8a53fcc4));
    printf("%d\n", *((int*) 0x8a53fce4));
    printf("%f\n", *((double*) 0x8a53fd08));
    return 0;
}
&a 0x8a53fca4 (char*) 0x8a53fca4
&b 0x8a53fcc4 (short*) 0x8a53fcc4
&c 0x8a53fce4 (int*) 0x8a53fce4
&d 0x8a53fd08 (double *)0x8a53fd08

小端序

12
34
56
78
#include <stdio.h>
int main(int argc, char* argv[]) {
   
   

    int data = 0x12345678;
    printf("%p\n",&data);
    printf("%#x\n",*(&data));
    //printf("%x\n",*((char*) 0000009CB7D2F574))

    printf("%x\n",*((char*)&data));  //对变量取地址 不仅取出了地址 还有类型
    printf("%x\n", *((short*)&data));
    printf("%x\n", *((int*)&data));

    return 0;
}
/*
0000009CB7D2F574
0x12345678
78
5678
12345678
指针的本质,是一个有类型的地址,类型决定了,从这个地址开始的寻址能力。
*/

指针变量

64位系统,这个位数指的是CPU 里面的通用寄存器的数据宽度为64位,也就是说一个地址占二进制位数是64,所以:sizeof(double )==sizeof(int )==sizeof(char *)==64/8==8。

32位系统,同理,他的一个地址占32位二进制空间,sizeof(double )==sizeof(int )==sizeof(char *)==32/8==4。

type * pointerName; *表明了本变量是指针变量,大小 此处的*仅能用于表示声明,类型决定了该指针变量中存储的地址的寻址能力。
#include <stdio.h>

//声明一个指针变量,必须要保存两种东西 一个地址数据 一个类型

//type * pointerName; *表明了本变量是指针变量,大小
int main(int argc, char* argv[]) {
   
   
    //int a = 12;
    //char c = 'c';
    //float d = 1.2f;
    char a; short b; int c; float f; double d;
    printf("%d\n",(sizeof(char *)));
    printf("%d\n", (sizeof(short *)));
    printf("%d\n", (sizeof(int *)));
    printf("%d\n", (sizeof(double *)));
    char* pa = &a;
    short* pb = &b;
    int* pc = &c;
    float* pf = &f;
    double* pd = &d;

    printf("%f\n", *pd);//printf("%f\n", *(&d));
    return 0;
}
/*
8
8
8
8
5.600000
*/
int main() {
   
   
    int data = 0x12345678;
    int* pd = &data;
    printf("%x\n", *pd);
    printf("%x\n", *((int*)pd));
    printf("%x\n", *((short*)pd));
    printf("%x\n", *((char*)pd));
    return 0;
}
/*
12345678
12345678
5678
78
*/
#include <stdio.h>


int main(int argc, char* argv[]) { 
    int arr[10];
    for (int i = 0; i < 10; i++) {
        printf("&arr[%d]= %p\n",i,&arr[i]);
        arr[i] = i;
    }
    for (int i = 0; i < 10;i++) {
        printf("%d\n", arr[i]);
        printf("%d\n", *(arr + i));
    }
    //代表构造类型/参与元素的访问,此时代表首元素的地址
    //arr 首元素地址
    printf("&arr[0] = %p\n", &arr[0]);
    printf("arr = %p\n", arr);
    printf("arr = %p\n", arr);
    printf("%d  %d\n",arr[1],1[arr]); //[]下标运算符  基址变址运算符
}
/*
&arr[8]= 0000009B60AFF808
&arr[9]= 0000009B60AFF80C
0
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
&arr[0] = 0000009B60AFF7E8
arr = 0000009B60AFF7E8
arr = 0000009B60AFF7E8
1  1
*/

函数

 可以提高程序开发的效率 。

 提高了代码的重用性 。

 使程序变得更简短而清晰。

 有利于程序维护。

int main() {
   
   
    srand(time(NULL));
    int i = rand() % 101; //0-100 + 100 100-200
    printf("%d\n",i);

    return 0;
}
#include <stdio.h>
#include <math.h>
#include <ctype.h>
int main() {
   
   
    double data = 9.0;
    double r = sqrt(data);
    printf("%f\n", r);
    double power = pow(data,3);
    printf("%f\n",power);

    printf("%f\n",ceil(3.14));//向上取整
    printf("%f\n", floor(3.14));//向下取整

    for (char ch = 'a';ch < 'z';ch ++){
   
   
        putchar(toupper(ch));
        //转小写tolower()
    }
    return 0;
}

自定义函数

#include <stdio.h>
int myMax(int , int);
//函数在调用的时候,输入的参数,通常叫做实参
//函数在定义或者声明的时候的参数,通常叫做形参。声明中的形参可以省略。
int main() {
   
   
    int a = 3, b = 5;
    int iMax = myMax(a,b);
    printf("%d\n",iMax);
    return 0;
}
int myMax(int i,int j){
   
   
    return i>j?i:j;
}

传值与传址

#include <stdio.h>
//进程空间
//函数在被调用之前,其内所有的变量尚未开辟空间。
//空间的开辟起始于函数调用,空间消失结束于函数调用完毕
//传值

void func(int a);

int main() {
   
   
    int a = 10;
    func(a);
    printf("a = %d\n", a);
    return 0;
}

void func(int a) {
   
   
    a++;
    printf("a=%d\n", a);
}
/*
11
10
*/
#include <stdio.h>
void func(int *pa);

int main() {
   
   
    int a = 10;
    func(&a);
    printf("a = %d\n", a);
    return 0;
}

void func(int *pa) {
   
   
    (*pa)++;
    printf("a=%d\n", *pa);
}
/*
11
11
*/

交换值

#include <stdio.h>
void mySwap(int *pa, int *pb);

int main() {
   
   
    int a = 10, b = 3;
    mySwap(&a, &b);
    printf("a = %d b = %d", a, b);
}

void mySwap(int *pa, int *pb) {
   
   
    int temp;
    temp = *pa;
    *pa = *pb;
    *pb = temp;
}

传递一维数组

#include <stdio.h>
//数组的传递不可能通过拷贝的方式来传递,C语言基于效率的原因,
// 只传递首地址
//数组有三要素,起始地址,步长 范围
//数组名,是一个指针包含了(起始地址和步长)但是数组名里面没有范围
//所以在传递一维数组的时候要传递 数组名和 范围

void disArray(int *p, int n);

int main() {
   
   

    int arr[] = {
   
   1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
//    for (int i = 0; i <10 ; ++i) {
   
   
//        printf("%d\n",arr[i]);
//    }
    printf("sizeof(arr) = %d\n", sizeof(arr));
    //disArray(&arr[0]);
    //disArray(arr);
    disArray(arr, sizeof(arr) / sizeof(arr[0]));
    return 0;
}

void disArray(int *p, int n) {
   
   
    for (int i = 0; i < n; i++) {
   
   
        printf("%d\n", *p++);
    }
}
/*
sizeof(arr) = 40
1
2
3
4
5
6
7
8
9
10
*/

用逻辑代数可以证明这种交换算法的正确性:易证异或运算满足交换律和结合律,则(a^b)^b=a^(b^b)=a^0=a(a^b)^a=a^(a^b)=(a^a)^b=0^b=b

选择排序

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void initRandArr(int *arr, int n) {
   
   
    srand(time(NULL));
    for (int i = 0; i < n; i++) {
   
   
        *arr++ = rand() % 100;
    }
}

void display(int *arr, int n) {
   
   
    for (int i = 0; i < n; ++i) {
   
   
        printf("%d\n", *arr++);
    }
}

int smallIndex(int startIdx, int *arr, int n) {
   
   
    int idx = startIdx;
    for (int i = startIdx + 1; i < n; ++i) {
   
   
        if (arr[i] < arr[idx])
            idx = i;
    }
    return idx;
}

void mySwap(int *pa, int *pb) {
   
   
    *pa ^= *pb;
    *pb ^= *pa;
    *pa ^= *pb;

}

void selectSort(int *arr, int n) {
   
   
    for (int i = 0; i < n; ++i) {
   
   
        int idx;
        idx = smallIndex(i, arr, n);
        if (idx != i) {
   
   
            mySwap(&arr[i], &arr[idx]);
        }
    }
}

int main() {
   
   
    int arr[10];
    initRandArr(arr, 10);
    display(arr, 10);
    selectSort(arr, 10);
    printf("------sort----- : \n");
    display(arr, 10);
    return 0;
}

如何传递二维数组

#include <stdio.h>
void func(int (*p)[4],int n){
   
   
    for (int i = 0; i < n; ++i) {
   
   
        for (int j = 0; j < 4; ++j) {
   
   
            printf("arr[%d][%d] = %d ",i,j,p[i][j]);
        }
        printf("\n");
    }
}
int main() {
   
   
    int arr[3][4]={
   
   {
   
   1},
                   {
   
   2,3},
                   {
   
   4,5,6}}; //int[4] arr[3]
    func(arr,3);
    return 0;
}

函数调用-递归

#include <stdio.h>

int getAge(int n){
   
   
    if (n==1){
   
   
        return 10;
    }else
        return getAge(n-1)+2;
}
int main() {
   
   
//直接或间接调用自己的情形,就是递归调用,recursive
//递归,是比较接近自然语言的特性的一种调用方式。递归必须要有合理的出口,不然会挂掉。
//递归起始条件getAge(5) 有使递归趋于结束的语句getAge(n-1) 递归终止条件n==1
    int age;
    printf("请输出要计算的年龄:");
    scanf("%d", &age);
    age = getAge(age);
    printf("%d\n", age);
    return 0;
}
#include <stdio.h>

int getAge(int n){
   
   
    if (n==10){
   
   
        return 1;
    }else
        return (getAge(n+1)+1)*2;
}
int main() {
   
   

    int peach ;

    peach = getAge(1);
    printf("%d\n", peach);
    return 0;
}

变量作用域/生命周期/修饰符

作用域Scope

函数的生命周期起于调用 结束于调用

局部变量的生命周期,起于调用,结束于调用结束

main 进程的开始和结束

修饰符

auto 只能用于修饰局部变量,该变量存储于stack

存储在stack上的参数有什么特点,随用随开 用完消失

默认的局部变量,就是auto类型的,通常将其省略 C++ auto

C语言 忘记

register

extern 跨文件使用 同文件使用

变量的声明与 定义 现在要区分了

extern 是可以省略的 但是不建议省略

static修饰局部变量

#include <stdio.h>

//static修饰局部变量,默认初始化为零
//auto 修饰的局部变量存储在栈上,随用即开 用完即清
//static 修改的局部变量, data
void func() {
   
   
    int a=1;
    printf("a = %d ", a++);
    static int b=1 ;
    printf("b = %d\n",b++);
    printf("++++++++++++\n");
}

int main() {
   
   
    for (int i = 0; i <10 ; ++i) {
   
   
        func();
    }

    return 0;
}

字符串常量

stack
heap
data 全局变量 static 局部变量 常量
text
字符串常量是由双引号,引起的一串字符。系统在字符串最后添加了一个字符'\0'
C语言 如何处理字符串,将其处理一个向data段字符的一个首地址
对比数组,三要素,起始地址,步长,范围
char* 可不可以代表整个字符串 起始地址 步长 '\0'  可以代表整个字符串
#include <stdio.h>

int main(){
   
   
    printf("sizeof(\"china\")=%d\n",sizeof("china"));
    int a = 10;
    int b = 20;
    printf("%s\n","china");
    char *p = "china";
    printf("p = %p  p+1 = %p  p[0] = %c 2[p] = %c\n",p,p+1,p[0],2[p]);
    printf("  = %p + 1  = %p       = %c           = %c\n","china","china"+1,"china"[0],2["china"]);


    printf("a = %d,b = %d ,p = %s\n",a,b,p);


    return 0;
}
/*
sizeof("china")=6
china
p = 00007ff75c98a014  p+1 = 00007ff75c98a015  p[0] = c 2[p] = i
  = 00007ff75c98a014 + 1  = 00007ff75c98a015       = c           = i
a = 10,b = 20 ,p = china
*/

字符串与字符数组

#include <stdio.h>

//正是因为字符数组和字符串,他们具有相同的性质
//所以为了要改变字符串的内容,通常将字符串,拷贝到字符数组中去。

//arr[6]是栈上的空间  "china" 是data 一块常量区域
int main(){
   
   
    char arr[6] = "china";
    printf("%d\n",sizeof(char));
    printf("sizeof(arr) = %d  arr = %p  arr + 1 = %p \t\n",sizeof(arr),arr,arr+1);
    printf("sizeof(\"china\") = %d  \"china\" = %p  \"china\" + 1 = %p \t\n",sizeof("china"),"china","china"+1);
    printf("%s\n",arr);
    printf("\"china\"=%s\n","china");
    return 0;
}
/*
1
sizeof(arr) = 6  arr = 0000004d93dff6da  arr + 1 = 0000004d93dff6db     
sizeof("china") = 6  "china" = 00007ff6f941a034  "china" + 1 = 00007ff6f941a035     
china
"china"=china
*/

字符数组和字符串之间的联系

等价 sizeof(字符数组)的大小 >= sizeof(字符串)的大小

#include <stdio.h>
//字符数组和字符串之间的相同性质。并不代表字符串可以与任意的字符串数组之间划等号
//等价    sizeof(字符数组)的大小 >= sizeof(字符串)的大小
int main() {
   
   
char arr[2] = "china";
    printf("arr = %s\n",arr);
    printf("%s\n","china");
    printf("%s\n","ch\0ina");
    char arr1[6] = "china\0";
    printf("%s\n",arr1);
    char ca[6] = "china"; //char[5] 不等价 字符数组长度小于 字符串长度 发生越界 字符串后面有系统自动加上的'\0'
    printf("ca = %s \n",ca);
    return 0;
}
/*
arr = ch����
china
ch
china
ca = china
*/

更好的做法:利用数组可以省略大小的特点,一句数组的大小自适应,这样避免浪费空间。

原生字符串处理

#include <stdio.h>
#include <string.h>

int myStrlen(char * arr){
   
   
    int len ;
    for (len  = 0;  *arr++; len++);
        return len;

}
int main() {
   
   

    char *p = "china";
    char arr[] = "china";
    int count = 0;
//    while(*p!=0){
   
   
//        p++;
//        count ++;
//
//    }
//    printf("china长度为 %d",count);
    int len = myStrlen(arr);
    int len1 = strlen(p);
    printf("china长度为 %d\n", len);
    printf("china长度为 %d", len1);
    return 0;
}
#include <stdio.h>
#include <string.h>

int main() {
   
   
    char firstName[30] = "chenxu";
    char lastName[30] = "yang";
    char *p, *q;
    p = firstName;
    q = lastName;
    while(*p) p++;
//    while(1){
   
   
//        *p = *q;
//        if(*q == 0)
//            break;
//        p++;
//        q++;
//    }
//    while(*p = *q){
   
   
//        p++;
//        q++;
//    }
    while(*p++ = *q++);
    printf("%s\n",firstName);
    return 0;
}
/*
chenxuyang
*/

多文件变成xx.h 与xx.c

image-20230307165754010

指针数组

一个数组中的各个元素都是字符指针,我们称该数组为字符指针数组,或指针数组。

#include <stdio.h>
//指针数组的本质是数组  数组指针的本质是指针
int main(){
   
   
//    char *pa="china",*pb="meri",*pc="canada",*pd="japan";
//    printf("pa = %p\n",pa);
//    printf("pb = %p\n",pb);
//    printf("pc = %p\n",pc);
//    printf("pd = %p\n",pd);
//    char * cqArr[4] = {pa,pb,pc,pd};;
//    for (int i = 0; i < 4; ++i) {
   
   
//        printf("cqArr = %p\n",cqArr[i]);
//    }
    char * pArr[] = {
   
   "china","meir","japan"};//字符指针数组
    for (int i = 0; i < 4; ++i) {
   
   
        printf("%p %s\n",pArr[i],pArr[i]);
    }
    return 0;
}
int main1() {
   
   
    int arr[] = {
   
   1,2,3,4,5};//整型数组
    char cArr[] = {
   
   'a','b','c','d','e'};//字符数组

    int a, b,c,d;
    int * intArr[] = {
   
   &a,&b,&c,&d}; //整型指针数组

    char aa,bb,cc,dd;
    char * cpArr[] = {
   
   &aa,&bb,&cc,&dd};//{char*,char*,char*,char*}字符指针数组

    char *pa="china",*pb="meri",*pc="canada",*pd="japan";
    char * cqArr[] = {
   
   pa,pb,pc,pd};;
    return 0;
}
/*
0x100403000 china
0x100403006 meir
0x10040300b japan
*/
#include <stdio.h>
#include <string.h>

int main() {
   
   
    char *pArr[] = {
   
   "china", "ameria", "canada", "japan"};
    for (int i = 0; i < 4; i++) {
   
   
        printf("%p %s\n", pArr[i], pArr[i]);
    }


    printf("%d\n", sizeof(pArr));
    int n = sizeof(pArr) / sizeof(*pArr);
    char *p;
    for (int i = 0; i < n - 1; i++) {
   
   
        for (int j = i + 1; j < n; j++) {
   
   
            if (strcmp(pArr[i], pArr[j]) > 0) {
   
   
                p = pArr[i];
                pArr[i] = pArr[j];
                pArr[j] = p;
            }
        }
    }
    for (int i = 0; i < 4; i++) {
   
   
        printf("%p %s\n", pArr[i], pArr[i]);
    }
    return 0;
}
/*
00007ff79209a000 china
00007ff79209a006 ameria
00007ff79209a00d canada
00007ff79209a014 japan
32
00007ff79209a006 ameria
00007ff79209a00d canada
00007ff79209a000 china
00007ff79209a014 japan
*/
#include <stdio.h>

//在启动进程,通过命令行,传递给进程的参数,即传递main的参数
//arg argment 参数  c    count 个数的意思   argc 参数的个数的意思
//argv arg    指针数组  v  vector  指针数组向量
int main(int argc, char *argv[]) {
   
   
    for (int i = 0; i < argc; i++) {
   
   
        printf("%s\n", argv[i]);
    }
    return 0;
}

栈内存与堆内存的基本概念

源程序 源代码

程序 可执行性文件

进程 时间概念 可执行文件被拉起,到结束的这一段过程,成为进程

进程空间 , 可执行性文件被拉起后 在内存中的分布情况

栈内存的内容

栈中存放任意类型的变量,但必须是auto类型修饰的,即自动类型的局部变量。

栈存储的特点

​ 随用随开,用完即消 内存的分配和销毁系统自动完成,不需要人工干预。

栈大小

​ 栈的大小并不大,它的意义并不在于存储大数据,而在于数据交换。而不适于大空间的申请

堆空间主要用于大内存的使用。

栈的发展方向 高地址向低地址

堆内存的特点

低地址向高地址

堆内存可以存放任意类型的数据,但需要自己申请与释放

堆大小

​ 堆大小,想像中的无穷大,对于栈来说,大空间申请。但实际使用中,受限于内存的大小和内存是否连续性。

//heap 内存,可以用于申请大空间 需要手动申请与释放
//malloc 是以字节为单位进行申请
//free 释放
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
   
   
    char * p = (char *) malloc(1024 * 1024 * 1024);
    if (p == NULL)
        printf("malloc error");
    strcpy(p, "abcd");
    printf("over\n");
    free(p);
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
   
   
    //基本数据类型在栈和堆上
    int a; a = 100;
    printf("a = %d\n", a);
    int *p = (int *) malloc(4);
    *p = 100;
    printf("*p = %d\n",*p);
    //数组类型在栈和堆上
    int arr[10] ;
    int *pa  = (int *) malloc(40);
    memset(pa,1,40);
    for (int i = 0; i <10 ; ++i) {
   
   
        printf("%d\n",pa[i]);
    }

    free(p);
    return 0;

}

结构体

凡是 基本类型,既可以在定义的时候初始化,也可以先定义再赋值

凡是构造类型,要么在定义的时候初始化,不可以先定义再以初始化的方式赋值

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

struct stu {
   
   
    char name[100];
    int num;
    char sex;
    float score;
};
//初始化是一种特殊的语法 跟赋值不等价
//凡是 基本类型,既可以在定义的时候初始化,也可以先定义再赋值
//凡是构造类型,在定义的时候初始化,不可以先定义再以初始化的方式赋值
int main() {
   
   
//int a; a = 10;
//int arr[10] = {1,2,4,5,6};
//arr = {1,2,3,4,5};
    struct stu s ;//= {"yangchengxu", 22, 'f', 99};
    strcpy(s.name,"zhangsan");
    s.num=1001;
    s.score=99;
    s.sex='f';

    printf("name: %s\n num: %d\n sex: %c\n score: %f\n",s.name,s.num,s.sex,s.score);
    return 0;

}
输出
name: zhangsan
 num: 1001
 sex: f
 score: 99.000000

静态链表

#include <stdio.h>
//静态链表的定义
typedef struct node {
   
   
    int data;
    struct node *next;
} Node;

int main() {
   
   
    //节点变量
    Node a, b, c, d, e;

    //定义头指针
    Node *head = &a;
    a.data = 1;
    b.data = 2;
    c.data = 3;
    d.data = 4;
    e.data = 5;
    a.next = &b;
    b.next = &c;
    c.next = &d;
    d.next = &e;
    e.next = NULL;
    //打印链表 元素内容一般 重新定义一个指针,如果使用head头指针,对其改动head的指向最后就变了
    //在这里只是打印 所以不定义新的指针变量
    Node * pa = head;
//    while (pa){
   
   
//        printf("data = %d\n",pa->data);
//        pa = pa->next;
//    }
    while (head) {
   
   
        printf("data = %d\n", head->data);
        head = head->next;
    }
    return 0;

}
/*
data = 1
data = 2
data = 3
data = 4
data = 5
*/

动态链表

链表的创建头插法与尾插法

尾插法

尾插法,在尾节点插入,每插入一个节点,即成尾节点

#include <stdio.h>
#include <stdlib.h>

typedef struct node {
   
   
    int data;
    struct node *next;
} Node;

Node *createList() {
   
   
    Node *head = (Node *) malloc(sizeof(Node));
    if (NULL == head) {
   
   
        exit(-1);
    }
    head->next = NULL;
    Node *t = head, *cur;
    int nodeData;
    scanf("%d", &nodeData);
    while (nodeData) {
   
   
        cur = (Node *) malloc(sizeof(Node));
        if (NULL == cur) {
   
   
            exit(-1);
        }
        cur->data = nodeData;
        t->next = cur;
        t = cur;
        scanf("%d", &nodeData);
    }
    t->next = NULL;
    return head;
}
void traverseList(Node * head){
   
   
    head = head->next;
    while(head){
   
   
        printf("data = %d\n",head->data);
        head = head->next;
    }
}
int main() {
   
   
    Node *head = createList();
    traverseList(head);
    return 0;
}
/*
3
2
1
0
data = 3
data = 2
data = 1
*/

头插法

所谓的头插法,就是在头节点后面插入元素,每插入一个元素即为首节点

让新来的节点先有所指向,避免打断原有的指向

#include <stdio.h>
#include <stdlib.h>

typedef struct node {
   
   
    int data;
    struct node *next;
} Node;
#if 0
Node *createList() {
   
   
    Node *head = (Node *) malloc(sizeof(Node));
    if (NULL == head) {
   
   
        exit(-1);
    }
    head->next = NULL;
    Node *t = head, *cur;
    int nodeData;
    scanf("%d", &nodeData);
    while (nodeData) {
   
   
        cur = (Node *) malloc(sizeof(Node));
        if (NULL == cur) {
   
   
            exit(-1);
        }
        cur->data = nodeData;
        t->next = cur;
        t = cur;
        scanf("%d", &nodeData);
    }
    t->next = NULL;
    return head;
}
#endif

Node *createList() {
   
   
    Node *head = (Node *) malloc(sizeof(Node));
    if (NULL == head) {
   
   
        exit(-1);
    }
    head->next = NULL;
    Node *cur;
    int nodeData;
    scanf("%d", &nodeData);
    while (nodeData) {
   
   
        cur = (Node *) malloc(sizeof(Node));
        if (cur == NULL)
            exit(-1);
        cur->data = nodeData;
        cur->next = head->next;
        head->next = cur;
        scanf("%d", &nodeData);
    }
    return head;
}


void traverseList(Node *head) {
   
   
    head = head->next;
    while (head) {
   
   
        printf("data = %d\n", head->data);
        head = head->next;
    }
}

int main() {
   
   
    Node *head = createList();
    traverseList(head);
    return 0;
}
/*
3 2 1 0
data = 1
data = 2
data = 3
*/

链表的插入

#include <stdio.h>
#include <stdlib.h>

typedef struct node {
   
   
    int data;
    struct node *next;
} Node;
//真正意义上的创建链表,就是创建一个空链表

Node *createList() {
   
   
    Node *head = (Node *) malloc(sizeof(Node));
    if (NULL == head) {
   
   
        exit(-1);
    }
    head->next = NULL;
    return head;
}

void insertList(Node * head,int nodedata){
   
   
    Node * cur = (Node *) malloc(sizeof(Node));
    if(NULL == head)
        exit(-1);
    cur->data = nodedata;
    cur->next = head->next;
    head->next = cur;
}

void traverseList(Node *head) {
   
   
    head = head->next;
    while (head) {
   
   
        printf("data = %d\n", head->data);
        head = head->next;
    }
}

int main() {
   
   
    Node *head = createList();
    for (int i = 0; i <5 ; ++i) {
   
   
        insertList(head,i);
    }
    traverseList(head);

    return 0;
}
/*
data = 4
data = 3
data = 2
data = 1
data = 0
*/

求长

int lenList(Node * head){
   
   
    int len =0;
    head=head->next;
    while(head){
   
   
        len ++;
        head=head->next;
    }
    return len;
}

删除

#include <stdio.h>
#include <stdlib.h>

typedef struct node {
   
   
    int data;
    struct node *next;
} Node;
//真正意义上的创建链表,就是创建一个空链表

Node *createList() {
   
   
    Node *head = (Node *) malloc(sizeof(Node));
    if (NULL == head) {
   
   
        exit(-1);
    }
    head->next = NULL;
    return head;
}

void insertList(Node *head, int nodedata) {
   
   
    Node *cur = (Node *) malloc(sizeof(Node));
    if (NULL == head)
        exit(-1);
    cur->data = nodedata;
    cur->next = head->next;
    head->next = cur;
}

void traverseList(Node *head) {
   
   
    head = head->next;
    while (head) {
   
   
        printf("data = %d\n", head->data);
        head = head->next;
    }
}

//求长 本质就是遍历
int lenList(Node *head) {
   
   
    int len = 0;
    head = head->next;
    while (head) {
   
   
        len++;
        head = head->next;
    }
    return len;
}

//查
Node *searchList(Node *head, int findData) {
   
   
    head = head->next;
    while (head) {
   
   
        if (head->data == findData)
            break;
        head = head->next;
    }
    return head;
}

//删
Node *deleteNodeOfList(Node *head, Node *pfind) {
   
   
    while (head->next != pfind)
        head = head->next;
    head->next = pfind->next;
    free(pfind);
}

int main() {
   
   
    Node *head = createList();
    for (int i = 0; i < 5; ++i) {
   
   
        insertList(head, i);
    }
    traverseList(head);
    int len = lenList(head);
    printf("len of list %d\n", len);

    Node *pfind = searchList(head, 0);
    if (pfind == NULL) {
   
   
        printf("find none\n");
    } else {
   
   
        //改
        // pfind->data = 1000;
        printf("find in List\n");
        deleteNodeOfList(head, pfind);
    }
    traverseList(head);

    return 0;


}
/*
data = 4
data = 3
data = 2
data = 1
data = 0
len of list 5
find in List
data = 4
data = 3
data = 2
data = 1
*/

删除优化

//删
Node *deleteNodeOfList(Node *head, Node *pfind) {
   
   
    if(pfind->next == NULL) {
   
   
        while (head->next != pfind)
            head = head->next;
        head->next = pfind->next;
        free(pfind);
    }else{
   
   
        printf("不是尾节点\n");
        Node *t = pfind->next;
        pfind->data = pfind->next->data;
        pfind->next = pfind->next->next;
        freee(t);
    }
}

冒泡排序

#include <stdio.h>
#define N 5

int main() {
   
   
    int arr[N] = {
   
   5, 4, 3, 2, 1};
    for (int i = 0; i < N - 1; ++i) {
   
   
        for (int j = 0; j < N - 1 - i; ++j) {
   
   
            if (arr[j] > arr[j + 1]) {
   
   
                arr[j] ^= arr[j + 1];
                arr[j + 1] ^= arr[j] ;
                arr[j] ^= arr[j + 1] ;
            }
        }
    }
    for (int i = 0; i <N ; ++i) {
   
   
        printf("arr[%d]=%d\n",i,arr[i]);
    }
    return 0;
}
/*
arr[0]=1
arr[1]=2
arr[2]=3
arr[3]=4
arr[4]=5
*/

链表排序

#include <stdio.h>
#include <stdlib.h>

typedef struct node {
   
   
    int data;
    struct node *next;
} Node;
//真正意义上的创建链表,就是创建一个空链表

Node *createList() {
   
   
    Node *head = (Node *) malloc(sizeof(Node));
    if (NULL == head) {
   
   
        exit(-1);
    }
    head->next = NULL;
    return head;
}

void insertList(Node *head, int nodedata) {
   
   
    Node *cur = (Node *) malloc(sizeof(Node));
    if (NULL == head)
        exit(-1);
    cur->data = nodedata;
    cur->next = head->next;
    head->next = cur;
}

void traverseList(Node *head) {
   
   
    head = head->next;
    while (head) {
   
   
        printf("data = %d\n", head->data);
        head = head->next;
    }
}

//求长 本质就是遍历
int lenList(Node *head) {
   
   
    int len = 0;
    head = head->next;
    while (head) {
   
   
        len++;
        head = head->next;
    }
    return len;
}

//查
Node *searchList(Node *head, int findData) {
   
   
    head = head->next;
    while (head) {
   
   
        if (head->data == findData)
            break;
        head = head->next;
    }
    return head;
}

//删
Node *deleteNodeOfList(Node *head, Node *pfind) {
   
   
    if (pfind->next == NULL) {
   
   
        while (head->next != pfind)
            head = head->next;
        head->next = pfind->next;
        free(pfind);
    } else {
   
   
        printf("不是尾节点\n");
        Node *t = pfind->next;
        pfind->data = pfind->next->data;
        pfind->next = pfind->next->next;
        free(t);
    }
}

//排序
void popSortList(Node *head) {
   
   
    int len = lenList(head);
    head = head->next;
    Node *p, *q;
    for (int i = 0; i < len; ++i) {
   
   
        p = head;
        q = head->next;
        for (int j = 0; j < len - 1 - i; ++j) {
   
   
            if (p->data > q->data) {
   
   
                p->data ^= q->data;
                q->data ^= p->data;
                p->data ^= q->data;
            }
            p = p->next;
            q = q->next;
        }
    }
}

int main() {
   
   
    Node *head = createList();
    for (int i = 5; i > 0; --i) {
   
   
        insertList(head, i);
    }
    traverseList(head);
    int len = lenList(head);
    printf("len of list %d\n", len);

    Node *pfind = searchList(head, 3);
    if (pfind == NULL) {
   
   
        printf("find none\n");
    } else {
   
   
        //改
        // pfind->data = 1000;
        printf("find in List\n");
        deleteNodeOfList(head, pfind);
    }
    traverseList(head);
    popSortList(head);
    printf("after sored: \n");
    traverseList(head);
    return 0;

}
/*
data = 1
data = 2
data = 3
data = 4
data = 5
len of list 5
find in List
不是尾节点
data = 1
data = 2
data = 4
data = 5
after sored: 
data = 1
data = 2
data = 4
data = 5
*/

快速排序

image-20230309220337923

image-20230309223411666

//排序2
void popSortList(Node * head){
   
   
    int len = lenList(head);
    Node *prep,*p,*q,*t;
    for (int i = 0; i <len - 1 ; ++i) {
   
   
        prep = head;
        p = head->next;
        q = p->next;
        for (int j = 0; j < len -1 -i; ++j) {
   
   
            if(p->data>q->data){
   
   
                prep->next=q;
                p->next=q->next;
                q->next=p;
                t = p;
                p = q;
                q = t;
            }

            prep = prep->next;
            p= p->next;
            q = p->next;
        }
    }
}

链表的销毁

image-20230309223538850

void destoryList(Node * head){
   
   
    Node * t;
    while(head){
   
   
        t = head;
        head = head->next;
        free(t);
    }
}
#include <stdio.h>
#include <stdlib.h>

typedef struct node {
   
   
    int data;
    struct node *next;
} Node;
//真正意义上的创建链表,就是创建一个空链表

Node *createList() {
   
   
    Node *head = (Node *) malloc(sizeof(Node));
    if (NULL == head) {
   
   
        exit(-1);
    }
    head->next = NULL;
    return head;
}

void insertList(Node *head, int nodedata) {
   
   
    Node *cur = (Node *) malloc(sizeof(Node));
    if (NULL == head)
        exit(-1);
    cur->data = nodedata;
    cur->next = head->next;
    head->next = cur;
}

void traverseList(Node *head) {
   
   
    head = head->next;
    while (head) {
   
   
        printf("data = %d\n", head->data);
        head = head->next;
    }
}

//求长 本质就是遍历
int lenList(Node *head) {
   
   
    int len = 0;
    head = head->next;
    while (head) {
   
   
        len++;
        head = head->next;
    }
    return len;
}

//查
Node *searchList(Node *head, int findData) {
   
   
    head = head->next;
    while (head) {
   
   
        if (head->data == findData)
            break;
        head = head->next;
    }
    return head;
}

//删
Node *deleteNodeOfList(Node *head, Node *pfind) {
   
   
    if (pfind->next == NULL) {
   
   
        while (head->next != pfind)
            head = head->next;
        head->next = pfind->next;
        free(pfind);
    } else {
   
   
        printf("不是尾节点\n");
        Node *t = pfind->next;
        pfind->data = pfind->next->data;
        pfind->next = pfind->next->next;
        free(t);
    }
}

//排序
//void popSortList(Node *head) {
   
   
//    int len = lenList(head);
//    head = head->next;
//    Node *p, *q;
//    for (int i = 0; i < len; ++i) {
   
   
//        p = head;
//        q = head->next;
//        for (int j = 0; j < len - 1 - i; ++j) {
   
   
//            if (p->data > q->data) {
   
   
//                p->data ^= q->data;
//                q->data ^= p->data;
//                p->data ^= q->data;
//            }
//            p = p->next;
//            q = q->next;
//        }
//    }
//}
//排序2
void popSortList(Node * head){
   
   
    int len = lenList(head);
    Node *prep,*p,*q,*t;
    for (int i = 0; i <len - 1 ; ++i) {
   
   
        prep = head;
        p = head->next;
        q = p->next;
        for (int j = 0; j < len -1 -i; ++j) {
   
   
            if(p->data>q->data){
   
   
                prep->next=q;
                p->next=q->next;
                q->next=p;
                t = p;
                p = q;
                q = t;
            }

            prep = prep->next;
            p= p->next;
            q = p->next;
        }
    }
}

void destoryList(Node * head){
   
   
    Node * t;
    while(head){
   
   
        t = head;
        head = head->next;
        free(t);
    }
}
int main() {
   
   
    Node *head = createList();
    for (int i = 5; i > 0; --i) {
   
   
        insertList(head, i);
    }
    traverseList(head);
    int len = lenList(head);
    printf("len of list %d\n", len);

    Node *pfind = searchList(head, 3);
    if (pfind == NULL) {
   
   
        printf("find none\n");
    } else {
   
   
        //改
        // pfind->data = 1000;
        printf("find in List\n");
        deleteNodeOfList(head, pfind);
    }
    traverseList(head);
    popSortList(head);
    printf("after sored: \n");
    traverseList(head);
    destoryList(head);
    return 0;


}
相关文章
|
6月前
|
C语言
C语言学习笔记-C语言中的数据类型
C语言学习笔记-C语言中的数据类型
|
6月前
|
C语言
C语言学习笔记-数组
C语言学习笔记-数组
|
6月前
|
C语言
C语言学习笔记-C语言中的运算符
C语言学习笔记-C语言中的运算符
|
11月前
|
存储 编译器 C语言
终于学会数组的使用啦~~~------C语言数组学习笔记详解
终于学会数组的使用啦~~~------C语言数组学习笔记详解
104 1
|
6月前
|
C语言
C语言学习笔记-C语言中的程序结构语句
C语言学习笔记-C语言中的程序结构语句
|
1月前
|
C语言
C语言学习笔记-知识点总结上
C语言学习笔记-知识点总结上
81 1
|
6月前
|
C语言
C语言学习笔记-初识C语言
C语言学习笔记-初识C语言
|
5月前
|
C语言
C语言学习笔记之初识字符串
C语言学习笔记之初识字符串
42 5
|
5月前
|
文件存储 C语言
|
5月前
|
存储 机器学习/深度学习 编译器
C语言代码学习笔记
<编程精粹:编写高质量C语言代码> 读书笔记