python編程,編程之基 --- C語言基礎大全 IV

 2023-11-18 阅读 33 评论 0

摘要:? BACK:編程之基 --- C語言基礎大全 III ? 流程一覽Tenth Week 字符串1. 字符串2. 字符串函數Eleventh Week 結構類型1. 枚舉2. 結構3. 聯合 Tenth Week 字符串 1. 字符串 以0(整數0)結尾的一串字符 0或’\0’是一樣的,但是和’0’不同 0標志字符

?

BACK:編程之基 --- C語言基礎大全 III
?

流程一覽

    • Tenth Week 字符串
      • 1. 字符串
      • 2. 字符串函數
    • Eleventh Week 結構類型
      • 1. 枚舉
      • 2. 結構
      • 3. 聯合

Tenth Week 字符串


1. 字符串

  • 以0(整數0)結尾的一串字符
    • 0或’\0’是一樣的,但是和’0’不同
  • 0標志字符串的結束,但它不是字符串的一部分
    • 計算字符串長度的時候不包含這個0
  • 字符串以數組的形式存在,以數組或指針的形式訪問
    • 更多的是以指針的形式
  • string.h里有很多處理字符串的函數

?

python編程?字符串變量:

char *str = "Hello";
char word[] = "Hello";
char line[10] = "Hello";

?

字符串常量1:

  • “Hello”
  • "Hello"會被編譯器變成一個字符數組放在某處,這個數組的長度是6,結尾還有表示結束的0
  • 兩個相鄰的字符串常量會被自動連接起來(可以用反斜杠\來分割字符串為上下兩行!但是第二行的兩個tab也會打印出來,所以第二行需要頂到最前面!)

?

字符串:

  • C語言的字符串是以字符數組的形態存在的
    • 不能用運算符對字符串做運算
    • 通過數組的方式可以遍歷字符串
  • 唯一特殊的地方是字符串字面量""可以用來初始化字符數組
  • 以及標準庫提供了一系列字符串函數

C語言編程。?

字符串常量2:

char *s = "Hello, world!";
  • s是一個指針,初始化為指向一個字符串常量
    • 由于這個常量所在的地方,所以實際上s是const char *s,但是由于歷史的原因,編譯器接受不帶const的寫法
    • 但是試圖對s所指的字符串做寫入會導致嚴重的后果
  • 如果需要修改字符串,應該用數組:
char s[] = "Hello, world!";

?

指針還是數組?

char *str = "Hello";
char word[] = "Hello";
  • 數組:這個字符串在這里,在一個固定的位置

    • 作為本地變量空間自動被回收
  • C語言基礎、指針:這個字符串不知道在哪里

    • 處理參數
    • 動態分配空間
  • 如果要構造一個字符串 ——> 數組方式

  • 如果要處理一個字符串 ——> 指針方式

?

char*是字符串?

  • 字符串可以表達為char*的形式
  • char*不一定是字符串
    • 本意是指向字符的指針,可能指向的是字符的數組(就像int*一樣)
    • 只有它所指的字符數組有結尾的0,才能說它所指的是字符串

編程語言有哪些,?

字符串輸入輸出:

  • char string[8];
    scanf("%s", string);
    printf("%s", string);
    
  • scanf讀入一個單詞(到空格、tab或回車為止)

  • scanf是不安全的,因為不知道要讀入的內容的長度

?

怎么編程、安全的輸入:

  • char string[8];
    scanf("%7s", string);
    
  • 在%和s之間的數字表示最多允許讀入的字符的數量,這個數字應該比數組的大小小一

    • 下一次scanf從哪里開始?(交給下一個%或者scanf去閱讀!)

?

常見錯誤:

  • char *string;
    scanf("%s", string);
    
  • 誤以為char*是字符串類型,定義了一個字符串類型的變量string就可以直接使用了,

    • 其實由于沒有對string初始化為0,可能指向的地址無害,則所以不一定每次運行都出錯

楊輝三角c語言編程。?

空字符串:

  • char buffer[100] = "";
    
    • 這是一個空的字符串,buffer[0] = ‘\0’
  • char buffer[] = "";
    
    • 這個數組的長度只有1!

?

字符串數組:寫一個數組表達很多個字符串

  • char **a;  // 非字符串數組
    
    • a是一個指針,指向另一個指針,那個指針指向一個字符(串)
  • char a[][10]; 
    char *a[];  // 字符串數組的兩種表達形式:第一種每個字符串有固定的長度,用數組來表示;而第二種沒有固定的長度,因為每個字符串是使用指針來表示的。
    

?

編程,程序參數:

  • int main(int argc, char const *argv[])
    
  • argc是argv的個數,argv[0]是命令本身,argv[0]后面的是命令行輸入的參數

    • 當使用Unix的符號鏈接時,反應符號鏈接的名字
#include <stdio.h>int main(int argc, char const *argv[]) {int i; for (i=0; i<argc; i++) {printf("%d:%s\n", i, argv[i]);}return 0;
}

?

2. 字符串函數

putchar:

  • int putcahr(int c);
    
  • 向標準輸出寫一個字符

  • 編程語言基礎-C語言。返回寫了幾個字符,EOF(-1)表示寫失敗

?

getchar:

  • int getchar(void);
    
  • 從標準輸入讀入一個字符

  • 返回類型是int是為了返回EOF(-1)

    • Windows ——> Ctrl-Z
    • Unix ——> Ctrl-D
#include <stdio.h>int main(int argc, char const *argv[]) {int ch;while ((ch=getcahr()) != EOF) {putchar(ch);}return 0;
}

c語言需要什么基礎、Crtl+C強制結束

Crtl+Z返回EOF(windows)

?

string.h:

  • strlen:返回字符串長度
  • strcmp:比較兩個字符串
  • strcpy:字符串拷貝
  • strcat:字符串相接
  • strchr:字符串中找字符
  • strstr:字符串中找字符串

?

C語言基礎教程?strlen:

  • size_t strlen(cosnt char *s);
    
  • 返回s的字符串長度(不包括結尾的0)

#include <stdio.h>
#include <string.h>size_t mylen(const char *s) {int idx = 0;while (s[idx] != '\0') {idx++;}return idx;
}int main(int argc, char const *argv[]) {char line[] = "Hello";printf("strlen=%lu\n", mylen(line));printf("sizeof=%lu\n", sizeof(line));return 0;
}

?

strcmp:

  • int strcmp(const char *s1, const char *s2);
    
  • 比較兩個字符串,根據ascii碼從左到右依次比較,返回:

    • 0:s1 == s2
    • 1:s1 > s2
    • -1:s1 < s2
#include <stdio.h>
#include <string.h>int mycmp(const char *s1, const char *s2) {// int idx = 0;// while (s1[idx]==s2[idx] && s1[idx]!='\0') {// 	 idx++;// }while (*s1==*s2 && s1!='\0') {s1++;s2++;}return *s1 - *s2
}int main(int argc, char const *argv[]) {char s1[] = "abc";char s2[] = "abc";printf("%d\n", mycmp(s1, s2));printf("%d\n", 'a'-'A');return 0;
}

c++編程、?

strcpy:

  • char* strcpy(char *restrict dst, const char *restrict src);
    
  • 把src的字符串拷貝到dst

    • restrict表明src和dst不重疊,為了多核性能(c99才有)
  • 返回dst

    • 為了能鏈起代碼來

?

c語言0基礎入門?復制一個字符串:

char *dst = (char*)malloc(strlen(src)+1);
strcpy(dst, src);
#include <stdio.h>
#include <string.h>char* mycpy(char *dst, const cahr *src) {// int idx = 0;// while (src[idx]) {//     dst[idx] = src[idx];//     idx++;// }// dst[idx] = '\0';char *ret = dst;while (*dst++ == *src++);*dst = '\0';return 0;
}int main(int argc, char const *argv[]) {char s1[] = "abc";char s1[] = "abc";strcpy(s1, s2);return 0;
}

?

strcat:

  • char* strcat(char *restrict s1, const char *restrict s2);
    
  • 把s2拷貝到s1的后面,接成一個長的字符串,會把s1最后的’\0’給覆蓋掉

  • 返回s1

  • C語言從入門到精通,s1必須具有足夠的空間

?

安全版本:目的地沒有足夠的空間

  • char* strncpy(char *restrict dst, const char *restrict src, size_t n);
    
  • char* strncat(char *restrict s1, const char *restrict s2, size_t n);
    
  • int strncpm(const char *s1, const char *s2, size_t n);  // 此函數的作用不是為了安全,是為了決定比較前n個的字符
    

?

字符串中找字符:

  • char* strchr(const char *s, int c);  // 返回找到的字符及其后面的字符串
    
  • char* strrchr(const char *s, int c);  // 從右開始找
    
  • 返回NULL表示沒有找到

  • 如何尋找第二個?

#include <stdio.h>
#include <string.h>
#include <stdlib.h>int main(int argc, char const *argv[]) {char s[] = "hello";char *p = strchr(s, 'l');char c = *p;*p = '\0';  // 返回字符l之前的字符串char *t = (char*)malloc(strlen(s)+1);strcpy(t, s);  // 把選定的字符的字符串復制到另一個變量printf("%s\n", t);free(t);return 0;
}

?

字符串中找字符串:

  • char* strstr(const char *s1, const char *s2);
    
  • char* strcasestr(const char *s1, const char *s2);  // 忽略大小寫
    

?
?

Eleventh Week 結構類型


1. 枚舉

常量符號化:

  • 用符號而不是具體的數字來表示程序中的數字
#include <stdio.h>const int red = 0;
const int yellow =1;
const int green = 2;int main(int argc, char const *argv[]) {int color = -1;char *colorName = NULL;printf("輸入你喜歡的顏色的代號:");scanf("%d", &color);switch (color) {case red: colorName = "red"; break;case yellow: colorName = "yellow"; break;case green: colorName = "green"; break;default: colorName = "unknown"; break;}printf("你喜歡的顏色是%s\n", colorName);return 0;
}

?

枚舉:

  • 用枚舉而不是定義獨立的const int變量
#include <stdio.h>enum COLOR {RED, YELLOW, GREEN};int main(int argc, char const *argv[]) {int color = -1;char *colorName = NULL;cprintf("輸入你喜歡的顏色的代號:");scanf("%d", &color);switch (color) {case RED: colorName = "red"; break;case YELLOW: colorName = "yellow"; break;case GREEN: colorName = "green"; break;default: colorName = "unknown"; break;}printf("你喜歡的顏色是%s\n", colorName);return 0;
}

?

枚舉:

  • 枚舉是一種用戶定義的數據類型,它用關鍵字enum以如下語法來聲明:

    enum 枚舉類型名字 {名字0, ..., 名字n};
    

?

  • 枚舉類型名字通常并不真的使用,要用的是在大括號里的名字,因為它們就是常量符號,它們的類型是int,值則依次從0到n。如:

    enum color {red, yellow, green};
    
  • 就創建了三個常量,red的值是0,yellow是1,而green是2。

  • 當需要一些可以排列起來的常量值時,定義枚舉的意義就是給了這些常量值名字。

?

  • 枚舉可以作為值
  • 枚舉類型可以跟上enum作為類型
  • 但是實際上是以整數來做內部計算和外部輸入輸出的
#include <stdio.h>enum color {red, yellow, green};void f(enum color c);int main(void) {enum color t = red;scanf("%d", &t);f(t);return 0;
}void f(enum color c) {printf("%d\n", c);
}

?

套路:自動計數的枚舉

  • 這樣需要遍歷所有的枚舉量或者需要建立一個用枚舉量做下標的數組的時候就很方便了
#include <stdio.h>enum COLOR {RED, YELLOW, GREEN, NumCOLORS};int main(int argc, char const *argv[]) {int color = -1;char *ColorNames[NumCOLORS] = {"red", "yellow", "green",};char *colorName = NULL;printf("輸入你喜歡的顏色的代碼:");scanf("%d", &color);if (color>=0 && color<NumCOLORS) {colorName = ColorName[color];} else {colorName = "unknown";}printf("你喜歡的顏色是%s\n", colorName);return 0;
}

?

枚舉量:

  • 聲明枚舉量的時候可以指定值

    • enum COLOR {RED=1, YELLOW, GREEN=5};
      
#include <stdio.h>enum COLOR {RED=1, YELLOW, GREEN=5, NumCOLORS};int main(int argc, char const *argv[]) {printf("code of GREEN is %d\n", GREEN);return 0;
}

?

枚舉只是int:

  • 即使給枚舉類型的變量賦不存在的整數值也沒有任何warning和error
#include <stdio.h>enum COLOR {RED=1, YELLOW, GREEN=5, NumCOLORS};int main(int argc, char const *argv[]) {enum COLOR color = 0;  // 本應該用符號量賦值,如:RED等。但未進行枚舉類型轉換,而直接用數字,是因為編譯器在這方面的放松,主要是這個不常用printf("code of GREEN is %d\n", GREEN);printf("and color is %d\n", color);return 0;
}

?

枚舉:

  • 雖然枚舉類型可以當作類型使用,但是實際上很少有,不好用
  • 如果有意義上排比的名字,用枚舉比const int方便
  • 枚舉比宏(macro)好,因為枚舉有int類型

?

主要作用:定義符號量,而不是當作類型使用。C的枚舉不太成功!主要是為了定義符號量。

?

2. 結構

聲明結構類型:

#include <stdio.h>int main(int argc, char const *argv[]) {struct date {int month;int day;int year;};  // 注意不要漏了這個分號!struct date today;today.month = 07;today.day = 31;today.year = 2014;printf("Today's date is %i-%i-%i.\n", today.year, today.month, today.day);return 0;
}

?

在函數內/外?

  • 和本地變量一樣,在函數內部聲明的結構類型只能在函數內部使用
  • 所以通常在函數外部聲明結構類型,這樣就可以被多個函數所使用了
#include <stdio.h>struct date {int month;int day;int year;
};int main(int argc, char const *argv[]) {struct date today;today.month = 07;today.day = 31;today.year = 2014;printf("Today's date is %i-%i-%i.\n", today.year, today.month, today.day);return 0;
}

?

聲明結構的形式:

  • 對于第一和第三種形式,都聲明了結構point。但是第二種形式沒有聲明point,只是定義了兩個變量。
struct point {int x;int y;
};
struct point p1, p2;  // p1和p2都是point里面有x和y的值struct {int x;int y;
} p1, p2;  // p1和p2都是一種無名結構,里面有x和ystruct point {int x;int y;
} p1, p2;  // p1和p2都是point里面有x和y的值

?

結構的初始化:

#include <stdio.h>struct date {int month;int day;int year;
};int main(int argc, char const *argv[]) {struct date today = {07, 31, 2014};struct date thismonth = {.month=7, .year=2014};  // 和數組一樣沒給的值添零printf("Today's date is %i-%i-%i.\n", today.year, today.month, today.day);printf("This month is %i-%i-%i.\n", thismonth.year, thismonth.month, thismonth.day);return 0;
}

?

結構成員:

  • 結構和數組有點像

  • 數組用[]運算符和下標訪問其成員

    • a[0] = 10;
      
  • 結構用.運算符和名字訪問其成員

    • today.day
      
    • student.firstName
      
    • p1.x
      
    • p1.y
      

?

結構運算:

  • 要訪問整個結構,直接用結構變量的名字

  • 對于整個結構,可以做賦值、取地址,也可以傳遞給函數參數

    • p1 = (struct point){5, 10};  // 相當于p1.x = 5; p1.y = 10;
      
    • p1 = p2;  // 相當于p1.x = p2.x; p1.y = p2.y;
      
  • 數組無法做這兩種運算!

?

結構指針:

  • 和數組不同,結構變量的名字并不是結構變量的地址,必須使用&運算符

  • struct date *pDate = &today;  // today本身無法打印?類似于int x
    

?

結構作為函數參數:

int numberOfDays(struct date d)
  • 整個結構可以作為參數的值傳入函數
  • 這時候是在函數內新建一個結構變量,并復制調用者的結構的值
  • 也可以返回一個結構
  • 這與數組完全不同

?

輸入結構:

  • 沒有直接的方式可以一次scanf一個結構
  • 如果我們打算寫一個函數來讀入結構
  • 但是讀入的結構如何送回來呢?
  • 記住C在函數調用時是傳值的
    • 所以函數中的p與main中的y是不同的
    • 在函數讀入了p的數值之后,沒有任何東西回到main,所以y還是{0, 0}
#include <stdio.h>struct point {int x;int y;
};void getStruct(struct point);
void output(struct point);void main() {struct point y = {0, 0};getStruct(y);output(y);
}void getStruct(struct point p) {scanf("%d", &p.x);scanf("%d", &p.y);printf("%d,%d", p.x, p.y);
}void output(struct point p) {printf("%d,%d", p.x, p.y);
}

?

解決的方案:

  • 之前的方案,把一個結構傳入了函數,然后在函數中操作,但是沒有返回回去
    • 問題在于傳入函數的是外面那個結構的克隆體,而不是指針
      • 傳入結構和傳入數組是不同的
  • 在這個輸入函數中,完全可以創建一個臨時的結構變量,然后把這個結構返回給調用者
struct point inputPoint() {struct point temp;scanf("%d", &temp.x);scanf("%d", &temp.y);return temp;
}void main() {struct point y = {0, 0};y = inputPoint();output(y);
}

?

指向結構的指針:

  • 用->表示指針所指的結構變量中的成員
struct date {int month;int day;int year;
} myday;struct date *p = &myday;(*p).month = 12;
p->month = 12;

?

  • ->用于結構體指針的
#include <stdio.h>struct point {int x;int y;
};struct point* getStruct(struct point*);
void output(struct point);
void print(cosnt struct point *p);int main(int argc, char const *argv[]) {struct point y = {0, 0};getStruct(&y);output(y);output(*getStruct(&y));print(getStruct(&y));getStruct(&y)->x = 0;  // 在賦值的左邊*getStruct(&y) = (struct point){1, 2};return 0;
}struct pint* getStruct(struct point *p) {scanf("%d", &p->x);scanf("%d", &p->y);printf("%d, %d", p->x, p->y);return p;  // 再傳回去一個指針是為了方便再運算
}void output(struct point p) {printf("%d, %d", p.x, p.y);
}void print(const struct point *p) {printf("%d, %d", p->x, p->y);
}

?

結構數組:

struct date dates[100];
struct date dates[] = {{4, 5, 2005},{2, 4, 2005}
};

?

結構中的結構:

struct dateAndTime {struct date sdate;struct time stime;
};

?

嵌套的結構:

struct point {int x;int y;
};
struct rectangle {struct point pt1;struct point pt2;
};// 如果有變量 struct rectangle r;
// 就可以有:r.pt1.x、r.pt1.y,r.pt2.x和r.pt2.y// 如果有變量定義:struct rectangle r, *rp; rp = &r;
// 那么下面的四種形式是等價的:
r.pt1.x
rp->pt1.x
(r.pt1).x
(rp->pt1).x
// 但是沒有rp->pt1->x(因為pt1不是指針)

?

結構中的結構的數組:

#include <stdio.h>struct point {int x;int y;
};struct rectangle {struct point p1;struct point p2;
};void printRect(struct rectangel r) {printf("<%d,%d> to <%d,%d>\n", r.p1.x, r.p1.y, r.p2.x, r.p2.y);
}int main(int argc, char const *argv[]) {int i;struct rectangle rects[] = {{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}};  // 2 rectanglefor (i=0; i<2; i++) printRect(rects[i]);return 0;
}

?

struct的內存大小是成員個數n*成員里占據最大空間的成員占據的空間,而地址是連續的,但是中間會有內存縫隙

?

3. 聯合

自定義數據類型:(typedef 方法看最后一個單詞是它的名字)

  • C語言提供了一個叫做 typedef 的功能來聲明一個已有的數據類型的新名字。比如:

    typedef int Length  // 使得Length成為int類型的別名
    
  • 這樣,Length這個名字就可以代替int出現在變量定義和參數聲明的地方了:

    Length a, b, len;
    Length numbers[10];
    

?

Typedef:聲明新的類型的名字

  • 新的名字是某種類型的別名
  • 改善了程序的可讀性
typedef long int64_t;  // 重載已有的類型名字,新名字的含義更清晰,具有可移植性
typedef struct ADate {int month;int day;int year;
} Date;  // 簡化了復雜的名字int64_t i = 100000000000;
Date d = {9, 1, 2005};

?

聯合:相似于struct

union AnElt {int i;char c;
} elt1, elt2;elt1.i = 4;
elt2.c = 'a';
elt2.i = 0xDEADBEEF;
  • 成員是
    • 一個int i還是
    • 一個char c
  • sizeof(union …) = sizeof(每個成員)的最大值

?

  • 存儲
    • 所有的成員共享一個空間
    • 同一時間只有一個成員是有效的
    • union的大小是其最大的成員
  • 初始化
    • 對第一個成員做初始化

?

  • 作用:可以得到一個int、double、flaot等內部的各個字節。

  • 文件操作,把一個整數以二進制的形式寫到文件里的時候,做讀寫的中間媒介。

#include <stdio.h>typedef union {int i;char ch[sizeof(int)];
} CHI;int main(int argc, char const *argv[]){CHI chi;unsigned int i;chi.i = 1234;for (i=0; i<sizeof(int); i++) {printf("%02hhX", chi.ch[i]);}printf("\n");return 0;
}

?

BACK:編程之基 --- C語言基礎大全 V
?

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://808629.com/176011.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 86后生记录生活 Inc. 保留所有权利。

底部版权信息