1.字符串與指針安全操作
核心函數與陷阱
函數 | 功能 | 安全替代 | 功能 |
---|---|---|---|
strcpy | 字符串拷貝 | strncpy | 復制前n個,最多strlen個,超出有效長度,按原樣復制 |
strcat | 字符串拼接 | strncat | dest只連接src的前n個,如果n超過有效長度,按原樣鏈接 |
strcmp | 字符串比較 | strncmp | 比較前n 個字符 |
strlen | 獲取有效長度(不含\0 ) |
const關鍵字與萬能指針
const關鍵字
????????1.普通變量經過const修飾后,會變為只讀變量,無法直接訪問,只能通過間接訪問修改。
2.指針變量前加const,不是說p不能改,而是*p不能改(p指向的變量),修飾的是*p(無法通過指針運算修改指針變量所指向的變量)
void*
萬能指針
- 可接收任意基類型指針,但不能做指針運算,可以降低程序的耦合性。
- 需強制類型轉換。
2.數組指針與指針數組
數組指針(指向數組的指針)
- 定義:指向數組的指針,括號不能省略,一維數組使用時,p+1為野指針。二維數組使用p + 1,不是野指針(二維數組作為函數參數傳遞,形參是指向一維數組的指針)。
int (*p)[4]
(指向含4個整數的數組)
3.函數與指針
指針函數(返回指針的函數)
- 禁止返回局部變量地址
// 錯誤示例
int* func() {int a = 10;return &a; // a銷毀后返回野指針
}
- 安全返回,用static修飾為靜態變量,或者直接用全局變量。
int* safe_func() {static int b = 20; // 靜態存儲期return &b; // 合法
}
4.關鍵技巧總結
- 字符串常量,內容相同時,地址是一樣的
void*
使用規范- 用于內存拷貝
memcpy
函數 - 用前必須強制類型轉換
- 用于內存拷貝
const
最佳實踐- 函數參數加
const
防止意外修改(如strlen(const char*)
)
- 函數參數加
4.代碼
? ? ? ? 1)字符串的操作
????????
void Puts(char *s)
{while(*s){putchar(*s++);}puts("");
}int Strlen(char *s)
{int counter = 0;while(*s){++counter;++s;}return counter;
}void Strcpy(char *dest, char *src)
{while(*src){*dest++ = *src++;}*dest = 0;
}void Strcat(char *dest, const char *src)
{while(*dest){++dest;}while(*src){*dest++ = *src++;}*dest = 0;
}int Strcmp(const char *s1,const char *s2)
{while(*s1 == *s2 && *s1 && *s2){++s1;++s2;}return *s1 - *s2;
}void Strncpy(char *dest, const char *src, int n)
{while(n--){*dest++ = *src++;}*dest = 0;
}void Memcpy(void *dest, const void *src, int n)
{char *p = (char *)src;char *q = (char *)dest;while(n--){*q++ = *p++;}*q = 0;
}void Strncat(char *dest, const char *src, int n)
{while(*dest){++dest;}while(n-- && *src){*dest++ = *src++;}*dest = 0;
}int Strncmp(const char *s1, const char *s2, int n)
{while(--n && *s1 == *s2 && *s1 && *s2){++s1;++s2;}return *s1 - *s2;
}int main(void)
{char s1[100] = "Hello";char s2[100] = "Helloq";//Puts(s1);//printf("%d\n", Strlen(s1));//Strcpy(s2, s1);//Puts(s2);//Strcat(s1, s2);//puts(s1);//printf("%d\n",Strcmp(s1,s2));//Strncpy(s2, s1, 5);//Puts(s2);//Memcpy(s2, s1, sizeof(s1));//Puts(s2);//Strncat(s2, s1, 8);//Puts(s2);//printf("%d\n", Strncmp(s1, s2, 5));return 0;
}
? ? ? ? 2)二維數組的操作(數組指針)
void printfArray2D(int (*a)[4], int rows)
{int i, j;for(i = 0;i < rows;++i){for(j = 0;j < 4;++j){printf("%2d ", *(*(a + i) + j));}puts("");}
}int sumOfArray2D(int (*a)[4], int rows)
{int i,j;int sum = 0;for(i = 0;i < rows;++i){for(j = 0;j < 4;++j){sum += *(*(a + i) + j);}}return sum;
}void swap(int *a, int *b)
{int t = *a;*a = *b;*b = t;
}void reverse(int *begin, int *end)
{while(begin < end){swap(begin, end);++begin;--end;}
}void reverse2D(int (*a)[4], int rows)
{int i;for(i = 0;i < rows;++i){reverse(*(a + i),*(a + i) + 4 - 1);}
}int main(void)
{int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};int rows = sizeof(a) / sizeof(a[0]);//printfArray2D(a, rows);//printf("%d\n", sumOfArray2D(a, rows));//reverse2D(a, rows);//printfArray2D(a, rows);return 0;
}
3)指針函數
char *Strcat(char *dest, const char *src)
{char *ret = dest;while(*dest){++dest;}while(*src){*dest++ = *src++;}*dest = 0;return ret;
}
5.總結
- 字符串操作:
strn
系列函數更安全。 - 嵌入式安全
const
保護只讀數據(如固件配置)- 靜態變量/全局變量保障指針生命周期
關聯知識:結合內存分區理解指針生命周期(棧/靜態區/堆)