C語言重點知識複習2

1.指針的算術運算
(1)指針之間不允許相加,但允許相減
指針相減表示兩個指針之間間隔的單元格數(1.先計算出字節數 2.再除以權重)
(2)指針運算需要調整
p+數字(n) 加n單元格的權重 權重爲指針變量去掉一個*,求sizeof(),乘n
數字之間不需要調整,直接加或減

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

int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9};
    int *p = arr; //指針-指針
    int *q = &arr[8];
    printf("%d\n",p-q);//-8
    printf("%d\n",q-p);//8
    printf("%d\n",(short *)q-(short *)p);//16
    printf("%d\n",(double *)q-(double *)p);//4
    printf("%d\n",(unsigned long)q-(unsigned long)p);//32


    int *p1 = (int *)2000;//指針+-數字
    printf("%d\n",p1+2);//2008
    printf("%d\n",(char *)p1+2);//2002
    printf("%d\n",(long long)p1+2);//2002
    printf("%d\n",(double **p1+2);//2008
}

2.數組和指針的替換

int arr[10];
int *p = arr;
arr[i] = *(arr+i);
p[i] = *(p+i);

3.指針和數組的其他知識
(1)數組名代表整個數組長度的兩種情況

int arr[10] = {0,1,2,3,4,5,6,7,8,9};
sizeof(arr) = 40;
cout<<&arr<<endl;//1000
cout<<&arr+1<<endl;//1040

(2)類型

int arr[10];   int *p = arr;
int brr[3][4]; int (*q)[4] = brr;//二維數組的數組名是指向一位數組的指針

brr[0]是int*類型
brr[0]+1是int*類型(+數字,對類型無影響)
brr[2][3]是int類型

(3)二位數組是否越界

int brr[3][4] = {{1,2,3},{4,5,6},{7}};  
printf("%d\n",brr[0][6]);//6  二維數組是線性存儲的,可以越界訪問

(4)字符串的定義正確的是?

char str1[5] = {'a','b','c'};//ok      
char str2[5] = {"abc"};//ok         
char str3[5] = "abc";//ok  
char str4[] = "hello"; //ok         
char str5[5] = "hello";//error,越界

(5)字符數組的大小
sizeof—求內存的字節數,所有的字符都要放進去
strlen—字符串的有效長度,碰到’\0’就結束

#include <stdio.h>

int main()
{
    char str1[100] = "abcde";
    char str2[100] = "abcd\0ef\n";
    char *str3 = "abcde";
    char *str4 = "abcd\0ef\n";
    char str5[] = "abcde";
    char str6[] = "abcd\0ef\n";
    printf("%d,%d\n",sizeof(str1),strlen(str1));//100,5
    printf("%d,%d\n",sizeof(str2),strlen(str2));//100,4
    printf("%d,%d\n",sizeof(str3),strlen(str3));//4,5
    printf("%d,%d\n",sizeof(str4),strlen(str4));//4,4
    printf("%d,%d\n",sizeof(str5),strlen(str5));//6,5
    printf("%d,%d\n",sizeof(str6,strlen(str6);//9,4
    return 0;
}

(6)字符數組和字符串常量的區別

int main()
{
    char *str1 = "abcde";//1   
    char str2[] = "abcde";//2   
    str1[0] = 'x';//3 編譯沒問題,運行崩潰
    str2[0] = 'x';//4
    return 0;
}

str1是字符常量,在全局靜態變量區(.rodata段),不能修改其值
str2是字符數組,在棧上,自己的內存,可以隨便修改
改錯題可能會考,需要在定義時顯示的加上const,這樣編譯就不會通過
const const char *str1 = “abcde”;

(7)下列各變量的含義

int *a;//整型指針
int *b();//函數,無參數,返回值是int *
int c[4];//整型數組
int *d[4];//指針數組,每個數組的元素是一個int類型的指針
int (*e)[4];//數組指針,該指針指向一個含有4個整型元素的數組
int (*f)();//函數指針,該指針指向一個函數,函數無參數,返回值是int類型

4.交換函數

#include <stdio.h>

void Swap1(int *p1, int *p2)
{
    int *tmp = p1;
    p1 = p2;
    p2 = tmp;
}

void Swap2(int *p1, int *p2)
{
    int *tmp;//野指針
    *tmp = *p1;
    *p1 = *p2;
    *p2 = *tmp;
} 

void Swap3(int *p1, int *p2)
{
    int tmp = *p1;
    *p1 = *p2;
    *p2 = tmp;
}

int main()
{
    int a = 10;
    int b = 20;
    printf("a=%d,b=%d\n",a,b);
    Swap1(&a, &b);
    printf("swap1:a=%d,b=%d\n",a,b);

    Swap2(&a, &b);
    printf("swap2:a=%d,b=%d\n",a,b);

    Swap3(&a, &b);
    printf("swap3:a=%d,b=%d\n",a,b);
    return 0;
}

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述
子函數和父函數之間要建立聯繫,必須傳指針並解引用

5.返回數組/指針

#include <stdio.h>
char *Fun1()
{
    char arr[] = "hello world";
    return arr;
}

int main()
{
    printf("%s\n",Fun1());///返回局部數組,亂碼
}`

這裏寫圖片描述
arr是局部變量,出Fun1函數後,函數棧幀回退,arr的地址可能已經被重新分配給別的函數使用。不能返回局部變量!!!

6.結構體和聯合體

struct A
{
    char a;//1+1
    short b;//2
    int c;//4
};//8

struct B
{
    char a;//1+3
    int b;//4
    short c;//2
};//10+2

struct C//位段
{
int a:10;//a佔10位
int b:2;//a佔2位
};//4,必須是int的倍數

struct D
{
    char a;//1
    struct DD//有類型有變量,以單個最大的數據類型對齊
    {
        char b;//1+3
        int c;//4
    }d;//8
};//9+3


struct E
{
       short a;//2
       struct EE//有類型沒變量,不佔內存
       {
           char b;
           int c;
       };//不佔內存
       int d;//4
};//6+2

struct F
{
    int a;//4
    struct//沒類型沒變量,生成一個透明的變量,a/b/c/d同級 
    {
        char b;//1+3
        float c;//4
    };
    char d;//1+3
};//16

struct G
{
       char a;//1
       struct//只有變量沒有類型(與有變量有類型)相同
       {
           char b;//1+3
           int c;//4
       }d;//8
};//9+3

union H//共用體
{
    char a;
    short b;
    int c;
};//4 

7.可變參數編程 3個宏

需要引入頭文件#include<stdarg.h>
va_list  list;//相當於char* list;
va_start(list, num);//找到...開頭
va_arg(list,int);//從…取數據
va_end(list);//list==NULL,關閉

編程題:編寫一個名叫max_list的函數,它用於檢查任意數目的整型參數並返回它們中的做大值,參數列表必須以一個負數結尾,提示列表的結束

#include <iostream>
#include <stdarg.h>
using namespace std;

int Max_list(int a,...)//1,4,9,-1
{
    int max = a;
    int cur = a;
    va_list list;//char *list;
    va_start(list,a);//找到...開頭

    while(cur >= 0)
    {
        cur = va_arg(list,int);//從...取數據
        if(max < cur)
        {
            max = cur;
        }
    }
    va_end(list);//list = NULL;
    return max;
}

int main()
{
    printf("%d\n",Max_list(1,5,9,0,2,5,-1));
    return 0;
}

8.malloc常見錯誤
這裏寫圖片描述
malloc一般都是內存的問題(程序崩潰/內存泄露)

面試題:C++是兼容C的,C已經有了malloc/free,C++爲什麼還要有new/delete?
答:malloc/free是C語言的標準庫函數,new/delete是C++的運算符
對於非內置數據類型的對象來說,使用malloc/free無法滿足動態創建對象的要求。對象創建的時候要自動調用構造函數,對象消亡的時候要自動調用析構函數。malloc/free是庫函數,不在編譯器權限的控制範圍內,不能把調用構造函數和析構函數的任務強加給malloc/free。因此,C++需要一個能完成動態分配並初始化內存的運算符new,一個可以清理並釋放內存的運算符delete。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章