-
B/S模型:浏览器/服务器模型;
-
C/S模型:客户端/服务器模型;
-
冒泡排序第一种写法:
//全部在主函数里的形式 #include <stdio.h> #include <stdlib.h> int main() { int a[] = { 6,4,8,9,4,7 }; int i = 0; int j = 1; int tmp = 0; int len = sizeof(a) / sizeof(int); for (i = 0; i < len-1; i++) { for (j = 0; j < len-1-i; j++) { if (a[j] < a[j+1]) { tmp = a[j]; a[j] = a[j+1]; a[j+1] = tmp; } } } for (i = 0; i < 6; i++) { printf("%d,", a[i]); } system("pause"); return 0; } //全部写成函数形式 #include <stdio.h> #include <stdlib.h> void swap(int *p1, int *p2) { int tmp; tmp = *p1; *p1 = *p2; *p2 = tmp; } void bubble_sort(int *a, int len) { for (int i = 0; i < len - 1; i++) { for (int j = 0; j < len - 1 - i; j++) { if (a[j] < a[j + 1]) { swap(&a[j], &a[j + 1]); } } } } void print(int *a, int len) { for (int i = 0; i < len; i++) { printf("%d,", a[i]); } } int main() { int a[] = { 6,4,8,9,4,7 }; int len = sizeof(a) / sizeof(int); bubble_sort(a, len); print(a, len); system("pause"); return 0; }
-
冒泡排序第二种写法:
//全部在主函数里的形式 #include <stdio.h> #include <stdlib.h> int main() { int a[] = { 6,4,8,9,4,7 }; int i = 0; int j = 1; int tmp = 0; int len = sizeof(a) / sizeof(int); for (i = 0; i < len; i++) { for (j = i+1; j < len; j++) { if (a[i] < a[j]) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } } } for (i = 0; i < len; i++) { printf("%d,", a[i]); } system("pause"); return 0; } //全部写成函数形式 #include <stdio.h> #include <stdlib.h> void swap(int *p1, int *p2) { int tmp; tmp = *p1; *p1 = *p2; *p2 = tmp; } void select_sort(int *a, int len) { for (int i = 0; i < len; i++) { for (int j = i + 1; j < len; j++) { if (a[i] < a[j]) { swap(&a[i], &a[j]); } } } } void print(int *a, int len) { for (int i = 0; i < len; i++) { printf("%d,", a[i]); } } int main() { int a[] = { 6,4,8,9,4,7 }; int len = sizeof(a) / sizeof(int); select_sort(a, len); print(a, len); system("pause"); return 0; }
-
简单选择排序
#include <stdio.h> #include <stdlib.h> #include<string.h> int selectsort(int *a, int len) { int max = 0; int tmp = 0; for (int i = 0; i < len-1; i++) { max = i; for (int j = i; j < len ;j++ ) { if (a[j] > a[max]) { max = j; } } tmp = a[i]; a[i] = a[max]; a[max] = tmp; } } int main() { int a[10] = { 0,3,5,7,9,4,2,8,6,10 }; selectsort(a, 10); for (int i = 0; i < 10; i++) { printf("%d ", a[i]); } return 0; }
-
快速排序
#include <stdio.h> #include <stdlib.h> #include<string.h> int print(int *a, int len) { for (int i = 0; i < len; i++) { printf("%d ", a[i]); } return 0; } int swap(int *a,int *b) { int tmp = 0; tmp = *a; *a = *b; *b = tmp; } int quicksort(int *a, int left, int right) { if (left < right) { int i = left; int j = right; int pivot = a[left]; do { do i++; while (a[i] < pivot); while (a[j] > pivot) j--; if (i < j) { swap(&(a[i]), &(a[j])); } } while (i < j); swap(&(a[left]), &(a[j])); quicksort(a, left, j - 1); quicksort(a, j + 1, right); } return 0; } int main() { int a[10] = { 3,5,7,9,0,4,6,8,1,2 }; int len = sizeof(a) / sizeof(a[0]); quicksort(a, 0, len-1); print(a, len); }
-
数组作函数参数会退化为指针;
-
定义一个数组b[5],b和&b代表的分别是数组首元素的地址和整个数组的地址,区别是指针步长不一样;
-
数据类型用于固定分配内存大小;
-
内存四区理想化模型:栈区,堆区,全局区(静态区),代码区;
-
栈是向下增长的,即从高地址往低地址增长,堆是向上增长的,即从低地址往高地址增长;栈的生长方向和数组增长方向是不同的。
-
证明栈的增长方向:
#include <stdio.h> #include <stdlib.h> void f2(); void f1() { int a ; printf("a:%d\n", &a); f2(); } void f2() { int b; printf("b:%d\n",&b); } int main() { f1(); system("pause"); }
-
指针是一种数据类型;
-
p1和p2的值有的编译器是相同的,有的是不同的
#include <stdio.h> #include <stdlib.h> char *getstr1() { char *p1 = "ttaa1"; return p1; } char *getstr2() { char *p2 = "ttaa1"; return p2; } int main() { char *p1 = getstr1(); char *p2 = getstr2(); printf("p1:%s,p2:%s\n", p1, p2); printf("p1:%d,p2:%d\n", &p1, &p2); system("pause"); return 0; }
-
函数的调用模型;
-
野指针产生原因:指针变量和它所指向的变量是两个不同的概念,释放了指针所指向的内存,没有将指针置为NULL。使用if(p!=NULL)语句无法判断,再次释放内存会出错,所以定义指针时初始化为NULL,释放后重新置为NULL;
-
改变指针变量的值相当于改变指针的指向;
-
字面量常量对应一种数据类型,其形式决定了它的数据类型,也可通过添加前缀和后缀改变字面量的类型;
-
从0级指针到一级指针
直接修改: #include <stdio.h> #include <stdlib.h> int main() { int a=0; a=20; int *p=&a; *p=30; printf("a=%d\n",a); system("pause"); return 0; } 间接修改: #include <stdio.h> #include <stdlib.h> void change(int *p) { *p=30; } int main() { int a=0; a=20; int *p=&a; change(p); printf("a=%d\n",a); system("pause"); return 0; }
-
从1级指针到2级指针:
直接修改: #include <stdio.h> #include <stdlib.h> int main() { int *p1=NULL; int *p2=NULL; p1=500; p2=&p1; *p2=600; printf("p1=%d\n",p1); system("pause"); return 0; } 间接修改: #include <stdio.h> #include <stdlib.h> void changep1(int **p2) { *p2=600; } int main() { int *p1=NULL; int *p2=NULL; p1=500; p2=&p1; changep1(p2); printf("p1=%d\n",p1); system("pause"); return 0; }
-
指针作函数参数间接赋值可以实现主函数与业务实现分层,间接赋值是指针存在的一个重要意义;
#include <stdio.h> #include <stdlib.h> void getmem(char **myp1, int *mylen1, char **myp2, int *mylen2) { *myp1 = (char *)malloc(20); strcpy(*myp1, "hello,"); *mylen1 = strlen(*myp1); *myp2 = (char *)malloc(20); strcpy(*myp2, "world"); *mylen2 = strlen(*myp2); } int main() { char *p1; int len1; char *p2; int len2; getmem(&p1, &len1, &p2, &len2); printf("len1=%d,p1=%s\n", len1, p1); printf("len2=%d,p2=%s\n", len2, p2); if (p1 != NULL) { free(p1); p1 = NULL; } if (p2 != NULL) { free(p1); p2 = NULL; } system("pause"); return 0; }
-
间接赋值成立的三个条件:
- 定义两个变量,一个实参,一个形参
- 建立关联
- 形参间接修改实参的值
-
间接赋值的三个条件应用场景:
- 1 2 3写在一个函数,主函数
- 1 2写在一块,3单独写在函数里,函数调用
- 1写在一块,2 3在一块,C++引用
-
用n级指针间接修改n-1级指针的值;
-
主调函数可以把栈区,堆区,全局区内存地址传给被调函数,被调函数只能返回堆区,全局区数据;
-
指针作函数参数是有输入和输出特性的;
-
指针作输入:在主调函数分配内存传给被调函数,指针作输出:在被调函数分配内存传给主调函数;
-
1级指针作输入常用的是数组,字符串;
-
C语言中没有字符串数据类型,通过字符数组模拟字符串;
-
字符串的内存分配,堆上,栈上,全局区;
-
char buf[20]={‘a’,‘b’,‘c’,‘d’},定义字符串“abcd”,char buf[]={‘a’,‘b’,‘c’,‘d’}是定义了一个数组,不是定义字符串;
-
用字符串初始化字符数组char buf[]=“abcd”;
-
通过数组下标和指针操作字符串
#include <stdio.h> #include <stdlib.h> int main() { int i=0; char buf[128]="abcdefg"; for(i=0;i<strlen(buf);i++) { printf("%c ",buf[i]); } printf("\n",buf[i]); char *p=buf; for(i=0;i<strlen(buf);i++) { printf("%c ",*(p+i)); } system("pause"); return 0; }
-
数组名代表数组首地址,是一个只读的指针,不能作buf=buf+1的操作;
-
字符串1级指针内存模型
#include <stdio.h> #include <stdlib.h> int main() { char buf[20]="aaa"; char buf2[]="bbb"; char *p1="ccc"; char *p2=(char *)malloc(100); strcpy(p2,"ddd"); system("pause"); return 0; }
-
字符串拷贝:
#include <stdio.h> #include <stdlib.h> int main() { char buf[]="abcdefg"; char buf2[20]; int i=0; for(i=0;buf[i]!='\0';i++) { buf2[i]=buf[i]; } buf2[i]='\0'; printf("%s\n",buf2); system("pause"); return 0; } 字符串作函数参数: #include <stdio.h> #include <stdlib.h> void arrycopy(char *from, char *to) { for (; *from != '\0'; from++, to++) { *to = *from; } *to = '\0'; } 可以写为: void arrycopy(char *from, char *to) { for (; *from != '\0'; ) { *to++ = *from++; } *to = '\0'; } 或者 void arrycopy(char *from, char *to) { while(*to=*from) { to++; from++; } } -> void arrycopy(char *from, char *to) { while(*to++=*from++) } -> void arrcopy(char *from,char *to) { while(*to++=*from++) { ; } } int main() { char *from = "abcdefg"; char buf2[20]; arrycopy(from, buf2); printf("%s\n", buf2); system("pause"); return 0; }
-
不要往指向NULL的指针拷贝数据;
-
不要轻易改变形参的值,可以用一个辅助的指针变量将形参接过来,再对辅助指针变量操作不影响形参
#include <stdio.h> #include <stdlib.h> void arrycopy(char *from, char *to) { char *myfrom = from; char *myto = to; while (*myto++ = *myfrom++); } int main() { char *from = "abcdefg"; char buf2[20]; arrycopy(from, buf2); printf("%s\n", buf2); system("pause"); return 0; }
-
do-while模型(求一个长字符串中含有一个短字符串的个数)
#include <stdio.h> #include <stdlib.h> int main() { char *p = "abcdaaaabcdbbbbabcdccc"; int count=0; do { p = strstr(p, "abcd"); if (p!=NULL) { count++; p = p + strlen("abcd"); } else break; } while (*p!= "\0"); printf("%d\n", count); system("pause"); return 0; }
while模型
#include <stdio.h> #include <stdlib.h> int main() { char *p = "abcdaaaabcdbbbbabcdccc"; int count=0; while (p= strstr(p, "abcd")) { count++; p = p + strlen("abcd"); if (*p == "\0") { break; } } printf("%d\n", count); system("pause"); return 0; }
函数接口模式:
do-while模型: #include <stdio.h> #include <stdlib.h> int arrycount(char *myp, char *mys, int *mycount) { if (myp == NULL || mys == NULL || mycount == NULL) { return -1; } char *p = myp; char *s = mys; int tmpcount = 0; do { p = strstr(p, s); if (p != NULL) { (tmpcount)++; p = p + strlen(s); } } while (p!=NULL); *mycount = tmpcount; return 0; } int main() { char *p = "abcdaaaabcdbbbbabcdccc"; char *s = "abcd"; int count = 0; int ret = arrycount(p, s, &count); if (ret != 0) { printf("func getCount() err:%d \n", ret); } printf("%d\n", count); system("pause"); return 0; } while模型: #include <stdio.h> #include <stdlib.h> int arrycount(char *myp, char *mys, int *mycount) { if (myp == NULL || mys == NULL || mycount == NULL) { return -1; } char *p = myp; char *s = mys; int tmpcount = 0; while (p = strstr(p, s)) { (tmpcount)++; p = p + strlen(s); } *mycount = tmpcount; return 0; } int main() { char *p = "abcdaaaabcdbbbbabcdccc"; char *s = "abcd"; int count=0; int ret = arrycount(p, s, &count); if (ret != 0) { printf("func getCount() err:%d \n", ret); } printf("%d\n", count); system("pause"); return 0; }
-
两头堵模型(求除去空格字符串的有效长度)
#include <stdio.h> #include <stdlib.h> int main() { char *s = " abcdefg "; int count = 0; int i = 0; int j = strlen(s) - 1; while (isspace(s[i])&&s[i]!="\0") { i++; } while (isspace(s[j]) && s[j] != "\0") { j--; } count = j - i + 1; printf("%d\n", count); system("pause"); return 0; } 函数模式: #include <stdio.h> #include <stdlib.h> int arrycount(char *s, int *count) { if (s == NULL || count == NULL) { return -1; } int i = 0; int j = strlen(s) - 1; while (isspace(s[i])&&s[i]!="\0") { i++; } while (isspace(s[j])&& s[j] != "\0") { j--; } *count = j - i + 1; return 0; } int main() { char *s = " abcdefg "; int count = 0; int ret = 0; ret = arrycount(s, &count); if (ret != 0) { printf("err\n"); } printf("%d\n", count); system("pause"); return 0; }
-
获得去空格的字符串
拷贝至新字符串 #include <stdio.h> #include <stdlib.h> #include<string.h> #pragma warning(disable : 4996) int trimspace(char *s, char *newarry) { int count = 0; if (s == NULL || newarry == NULL) { return -1; } int i = 0; int j = strlen(s) - 1; while (isspace(s[i]) && s[i] != "\0") { i++; } while (isspace(s[j]) && s[j] != "\0") { j--; } count = j - i + 1; strncpy(newarry, s+i, count); return 0; } int main() { char *s = " abcdefg "; int count = 0; int ret = 0; char newarry[20] = { 0 }; ret = trimspace(s, newarry); if (ret != 0) { printf("err\n"); } printf("%s\n", newarry); system("pause"); return 0; } 拷贝至原字符串: #include <stdio.h> #include <stdlib.h> #include<string.h> #pragma warning(disable : 4996) int trimspace(char *s) { int count = 0; if (s == NULL ) { return -1; } int i = 0; int j = strlen(s) - 1; while (isspace(s[i]) && s[i] != "\0") { i++; } while (isspace(s[j]) && s[j] != "\0") { j--; } count = j - i + 1; char tmp[20] = { 0 }; strncpy(tmp, s + i, count); memset(s, 0, strlen(s)); strncpy(s, tmp, count); strcat(s, "\0"); return 0; } int main() { char s[] = " abcdefg "; int count = 0; int ret = 0; ret = trimspace(s); if (ret != 0) { printf("err\n"); } printf("%s\n", s); system("pause"); return 0; }
-
字符串反转模型:
方法1: #include <stdio.h> #include <stdlib.h> #include<string.h> #pragma warning(disable : 4996) int inverse(char *s) { if (s == NULL) { return -1; } char *p1 = s; char *p2 = s + strlen(s) - 1; char tmp; while (p1 < p2) { tmp = *p1; *p1 = *p2; *p2 = tmp; p1++; p2--; } return 0; } int main() { char s[] = "abcdefg"; int ret = 0; ret = inverse(s); if (ret != 0) { printf("err\n"); } printf("%s\n", s); system("pause"); return 0; } 方法2: 递归: 打印: #include <stdio.h> #include <stdlib.h> #include<string.h> #pragma warning(disable : 4996) int inverse(char *s) { if (s == NULL) { return; } if (*s == 0)//不能写"\0",不知道是不是编译器的原因 { return; } inverse(s + 1); printf("%c", *s); } int main() { char s[] = "abcdefg"; int ret = 0; inverse(s); system("pause"); return 0; } 全局变量法: 初版: #include <stdio.h> #include <stdlib.h> #include<string.h> #pragma warning(disable : 4996) char tmp[20]; int i = 0; int inverse(char *s) { if (s == NULL) { return; } if (*s == '\0') { return; } inverse(s + 1); tmp[i] = *s; i++; } int main() { char s[] = "abcdefg"; inverse(s); memset(tmp,0,sizeof(tmp)); strncpy(s, tmp, strlen(s)); strcat(s, "\0"); printf("%s\n", s); system("pause"); return 0; } 修正版: #include <stdio.h> #include <stdlib.h> #include<string.h> #pragma warning(disable : 4996) char tmp[20]; int inverse(char *s) { if (s == NULL) { return; } if (*s == '\0') { return; } inverse(s + 1); strcat(tmp, s); } int main() { char s[] = "abcdefg"; inverse(s); memset(tmp,0,sizeof(tmp)); strncpy(s, tmp, strlen(s)); printf("%s\n", s); system("pause"); return 0; } 局部变量法: #include <stdio.h> #include <stdlib.h> #include<string.h> #pragma warning(disable : 4996) int inverse(char *s,char *mybuf) { if (s == NULL) { return; } if (*s == '\0') { return; } inverse(s + 1, mybuf); strncat(mybuf, s, 1); } int main() { char s[] = "abcdefg"; char mybuf[20] = { 0 };必须初始化,不然strcat函数识别不了是字符串,可以初始化为零,也可以为任意字符串,初始化可以使用memset函数 inverse(s,mybuf); printf("%s\n", mybuf); system("pause"); return 0; }
-
根据keybuf获得等号后面非空字符串:
#include <stdio.h> #include <stdlib.h> #include<string.h> #pragma warning(disable : 4996) int getarryvalue(char *buf,char *keybuf,char *valuebuf) { if (buf == NULL || keybuf == NULL || valuebuf == NULL) { return -1; } char *p = buf; p = strstr(p, keybuf); if (p == NULL) { printf("not found key\n"); return -1; } p = strstr(p, "="); if (p == NULL) { printf("not found =\n"); return -1; } p = p + strlen("="); int count = 0; int i = 0; int j = strlen(p) - 1; while (isspace(p[i]) && p[i] != "\0") { i++; } while (isspace(p[j]) && p[j] != "\0") { j--; } count = j - i + 1; strncpy(valuebuf, p + i, count); return 0; } int main() { char *s1 = " key1= hdghdhks"; char *s2 = "key2"; char *s3 = " key3 =ggtgt "; char valuebuf[50] = { 0 }; int ret = 0; ret = getarryvalue(s3, "key3", valuebuf); if (ret != 0) { printf( "err\n" ); } printf("%s\n", valuebuf); system("pause"); return 0; }
-
C语言中主函数调用其他函数中时,其中的参数与被调函数实际的参数个数不同,编译会检查不出来,这是C语言的一个灰色地带;
-
*count++,因为++优先级高,所以先取指针变量所指向的值,指针变量再加1而非指针指向的值加1,原本意思是要指针变量指向的值++,这样只有指针变量++,指向的值没变,所以要指向的值加1必须加括号;
-
const修饰*号,表示指针指向的值不能变,const修饰指针变量,指针的指向不能变;
-
C语言中的const修饰的东西并不是真正的不能修改,都可以通过指针进行修改;
-
指针作输出模型:
#include <stdio.h> #include <stdlib.h> #include<string.h> #pragma warning(disable : 4996) int getmem(char **myp, int *len) { *myp = (char *)malloc(100); strcpy(*myp, "aabbccdd"); *len = strlen(*myp); return 0; } int freemem(char *myp)//如果要将指针置成NULL,需要传二级指针,如下面程序 { if (myp != NULL) { free(myp); } return 0; } int main() { char *p1 = NULL; int ret = 0; int len = 0; ret = getmem(&p1, &len); if (ret != 0) { printf("p1 err\n"); } printf("%s,%d", p1,len); freemem(p1); system("pause"); return 0; } #include <stdio.h> #include <stdlib.h> #include<string.h> #pragma warning(disable : 4996) int getmem(char **myp, int *len) { *myp = (char *)malloc(100); strcpy(*myp, "aabbccdd"); *len = strlen(*myp); return 0; } int freemem(char **myp)//如果要将指针置成NULL,需要传二级指针,如下面程序 { if (myp == NULL) { return -1; } if (*myp != NULL) { free(*myp); } *myp = NULL; return 0; } int main() { char *p1 = NULL; int ret = 0; int len = 0; ret = getmem(&p1, &len); if (ret != 0) { printf("p1 err\n"); } printf("%s,%d", p1,len); freemem(&p1); system("pause"); return 0; }
-
指针作输入模型:
第1种: #include <stdio.h> #include <stdlib.h> #include<string.h> #pragma warning(disable : 4996) int print(char **s, int num) { if (s == NULL) { return -1; } for (int i = 0; i < num; i++) { printf("%s\n", s[i]); } } int sortarry(char **s, int num) { if (s == NULL) { return -1; } char *tmp; for (int i = 0; i < num; i++) { for (int j = i+1; j < num; j++) { if (strcmp(s[i], s[j])>0) { tmp = s[i]; s[i] = s[j]; s[j] = tmp; } } } } int main() { char *s[] = { "aaaaa","bbbbbbb","cccc","dddddddd "};//s指针在栈区,s[1],s[2].....指向全局区的数据,指针步长是4 int num = sizeof(s) / sizeof(s[1]); sortarry(s, num); print(s, num); system("pause"); return 0; } 第2种: #include <stdio.h> #include <stdlib.h> #include<string.h> #pragma warning(disable : 4996) int print(char (*s)[10], int num) { if (s == NULL) { return -1; } for (int i = 0; i < num; i++) { printf("%s\n", s+i); } } int sortarry(char(*s)[10], int num) { if (s == NULL) { return -1; } char tmp[20]; for (int i = 0; i < num; i++) { for (int j = i+1; j < num; j++) { if (strcmp(s[i], s[j])<0) { strcpy(tmp, s[i]);//交换的不再是指针,交换指针所指的数据 strcpy(s[i], s[j]); strcpy(s[j], tmp); } } } } int main() { char s[][10] = { "aaaaa","bbbbbbb","cccc","dddddddd "};//指针和数据都在栈区,指针步长是s[1]的长度 int num = sizeof(s) / sizeof(s[1]); sortarry(s, num); print(s, num); system("pause"); return 0; } 第3种: #include <stdio.h> #include <stdlib.h> #include<string.h> #pragma warning(disable : 4996) char **getmem(int size1, int size2) { int i = 0; char **p = (char **)malloc(sizeof(char *) * size1); for (i = 0; i < size1; i++) { p[i] = (char *)malloc(sizeof(char) * size2); } for (i = 0; i < size1; i++) { sprintf(p[i], "%d%d%d", i, i, i); } return p; } int freemem(char ***p, int size) { int i = 0; for (i = 0; i < size; i++) { if (*(*p + i) != NULL) { free(**p + i); *(*p + i) = NULL; } } if (*p != NULL) { free(*p); *p = NULL; } } int print(char **s, int num) { if (s == NULL) { return -1; } for (int i = 0; i < num; i++) { printf("%s\n", s[i]); } } int sortarry(char **s, int num) { if (s == NULL) { return -1; } char *tmp; for (int i = 0; i < num; i++) { for (int j = i + 1; j < num; j++) { if (strcmp(s[i], s[j])<0) { tmp = s[i]; s[i] = s[j]; s[j] = tmp; } } } } int main() { int i = 0; char **s = getmem(10, 20);//二级指针在栈区,一级指针在堆区,数据在堆区,指针步长是4 sortarry(s, 10); print(s, 10); //freemem(&s,10); system("pause"); return 0; }
-
指针作函数参数用n级指针改变n-1级指针的值;
-
两个辅助指针变量挖字符串(以","分隔将分隔后的字符串拷贝到一个二维数组或者一个二级指针指向的内存空间,并求出分隔后有多少个字符串)
#include <stdio.h> #include <stdlib.h> #include<string.h> #pragma warning(disable : 4996) int getvalue(char *s, char(*a)[30], char *c, int *rowcount) { if (s == NULL || rowcount == NULL) { return -1; } char *p = s; char *ptmp = s; int tmpcount = 0; while (p != NULL) { p = strstr(p, c); if (p - ptmp > 0) { strncpy(a[tmpcount], ptmp, p - ptmp); a[tmpcount][p - ptmp] = '\0'; tmpcount++; ptmp = p = p + 1; } } if (*ptmp != '\0') { strncpy(a[tmpcount], ptmp, strlen(ptmp) + 1); tmpcount++; } *rowcount = tmpcount; return 0; } int main() { char *s = "afdgg,ddddf,dsaff,ddfff"; char *c = ","; char a[20][30]; int rowcount = 0; int ret = 0; ret = getvalue(s, a, c, &rowcount); if (ret != 0) { printf("err\n"); } for (int i = 0; i < rowcount; i++) { printf("%s\n", a[i]); } printf("%d\n", rowcount); system("pause"); return 0; } 用第3种内存模型接: #include <stdio.h> #include <stdlib.h> #include<string.h> #pragma warning(disable : 4996) int getmem(char ***p,int size1, int size2) { int i = 0; *p = (char **)malloc(sizeof(char *) * size1); for (i = 0; i < size1; i++) { (*p)[i] = (char *)malloc(sizeof(char) * size2); } return 0; } int freemem(char ***p, int size) { int i = 0; for (i = 0; i < size; i++) { if ((*p)[i] != NULL) { free((*p)[i]); (*p)[i] = NULL; } } if (*p != NULL) { free(*p); *p = NULL; } } int getvalue(char *s, char **a,char *c, int *rowcount) { if (s == NULL || rowcount == NULL) { return -1; } char *p = s; char *ptmp = s; int tmpcount = 0; while(p = strstr(p, c)) { if (p - ptmp > 0) { strncpy(a[tmpcount], ptmp, p - ptmp); a[tmpcount][p-ptmp] = '\0'; tmpcount++; ptmp = p = p + 1; } } if (*ptmp != '\0') { strncpy(a[tmpcount], ptmp, strlen(ptmp) + 1); tmpcount++; } *rowcount = tmpcount; return 0; } int main() { char *s = "afdgg,ddddf,dsaff,ddfff"; char *c = ","; char **a = NULL; int ret = 0; ret = getmem(&a, 20, 30); if (ret != 0) { printf("err\n"); } int rowcount = 0; ret = getvalue(s, a, c, &rowcount); if (ret != 0) { printf("err\n"); } for (int i = 0; i < rowcount; i++) { printf("%s\n", a[i]); } printf("%d\n", rowcount); freemem(&a, 20); system("pause"); return 0; }
-
一个入口多个出口的函数,需要考虑前面return执行,直接跳过了释放内存的语句,可以使用goto语句,在函数后面添加释放内存的语句,goto跳到此处;
-
int c[10];数组名c和&c是不同的,c是首元素的地址,&c是整个数组的地址,指针步长不一样,c指针步长4个字节,&c指针步长40个字节;
-
怎么表达数组类型:
typedef int (arry)[5];//int后面有无空格都行 arry myarry;//相当于int myarry[5] #include <stdio.h> #include <stdlib.h> #include<string.h> int main() { typedef int(arry)[5]; arry myarry; for (int i = 0; i < 5; i++) { myarry[i] = i + 2; } for (int i = 0; i < 5; i++) { printf("%d ", myarry[i]); } system("pause"); return 0; }
-
数组指针类型
int a[5]; typedef int(*arry)[5]; arry myarry; myarry=a; #include <stdio.h> #include <stdlib.h> #include<string.h> int main() { int a[5]; typedef int(*arry)[5]; arry myarry; myarry = &a;//为了兼容,编译器允许a和&a都行 for (int i = 0; i < 5; i++) { (*myarry)[i] = i + 2; } for (int i = 0; i < 5; i++) { printf("%d ", (*myarry)[i]); } system("pause"); return 0; } 第一种方法 #include <stdio.h> #include <stdlib.h> #include<string.h> int main() { int *a[5] = { "asadd","dffa","sfff","hghth","gdhdhdh" }; typedef int(arry)[5]; arry *myarry; myarry = &a; for (int i = 0; i < 5; i++) { printf("%s ", (*myarry)[i]); } system("pause"); return 0; } 第二种方法 #include <stdio.h> #include <stdlib.h> #include<string.h> int main() { int *a[5] = { "asadd","dffa","sfff","hghth","gdhdhdh" }; typedef int(*arry)[5]; arry myarry; myarry = &a; for (int i = 0; i < 5; i++) { printf("%s ", (*myarry)[i]); } system("pause"); return 0; } 第三种方法 #include <stdio.h> #include <stdlib.h> #include<string.h> int main() { int *a[5] = { "asadd","dffa","sfff","hghth","gdhdhdh" }; int(*myarry)[5]; myarry = &a; for (int i = 0; i < 5; i++) { printf("%s ", (*myarry)[i]); } system("pause"); return 0; }
-
多维数组名的本质是数组指针;
-
数组种[]和*操作符的转换;
-
多维数组做函数参数,退化为数组指针;
-
多维数组是在内存上是线性存储的;
-
多维数组作函数参数,一般只能表达到二维,如果是三级及以上的指针,则不代表几维的内存;
-
分清指针数组*p[]和数组指针(*p)[]的区别;
-
指针数组的应用场景:菜单,命令行
菜单: #include "stdio.h" #include "string.h" #include "stdlib.h" #include <stdio.h> #include <string.h> #define DIM(a) (sizeof(a)/sizeof(*a)) int searcheKeyTable(const char* table[], const int size, const char* key, int *pos) { int rv = 0; int i = 0; int inum = 0; if (table == NULL || key == NULL || pos == NULL) { rv = -1; printf("func searcheKeyTable:%d", rv); return rv; } for (i = 0; i<size; i++) { if (strcmp(key, table[i]) == 0) { *pos = i; //break; return rv; } } //没有找到返回-1 if (i == size) { *pos = -1; } return rv; } int main() { int inum = 0; int pos = 0; int a[10]; int i = 0; //指针数组 char* c_keyword[] = { "while", "case", "static", "do" }; searcheKeyTable(c_keyword, DIM(c_keyword), "do", &pos); printf("pos:%d\n", pos); searcheKeyTable(c_keyword, DIM(c_keyword), "static", &pos); printf("pos:%d\n", pos); system("pause"); return; } 命令行: /* argc 命令行参数 argv 命令行参数数组 env 函数变量数组 int main(); int main(int argc); int main(int argc, char *argv[]) */ #include "stdio.h" #include "string.h" #include "stdlib.h" #include <stdio.h> #include <string.h> int main(int argc, char* argv[], char**env) { int i = 0; printf("******************* Begin argv *******************\n"); for (i = 0; i<argc; i++) { printf("%s\n", argv[i]); } printf("******************* End argv *******************\n"); printf("\n"); printf("\n"); printf("\n"); printf("******************* Begin env *******************\n"); for (i = 0; env[i] != NULL; i++) { printf("%s\n", env[i]); } printf("******************* End env*******************\n"); getchar(); }
-
指针数组结束的3种表示方法,’\0\、0和NULL;
-
结构体的定义方法和初始化的方法,typedef;
-
结构体中.和->操作是在CPU中计算结构体成员对于结构体的偏移量;
-
结构体变量的拷贝
#include <stdio.h> #include <stdlib.h> #include<string.h> typedef struct Teacher { int age; char name[64]; }Teacher; int copystruct(Teacher *to, Teacher *from) { *to = *from; return 0; } int main() { Teacher t1 = { 30,"aa" }; Teacher t2; copystruct(&t2, &t1); printf("%d,%s", t2.age, t2.name); return 0; }
-
指针数组求指针的个数
char *p1[] = { "aaa","ddddd","cccc","eeeee" }; int len = sizeof(p) / sizeof(*p);
-
二维数组求行数和列数
char p[][10] = { "qfef","ggrgrg","rgrggrg","hhhhdd" }; int len1 = sizeof(p2) / sizeof(p2[0]);//求行数 int len2 = sizeof(p2[0]) / sizeof(p[0][0]));//求列数
-
将第1种和第2种内存模型拷贝到第三种模型并排序
#include <stdio.h> #include <stdlib.h> #include<string.h> int getmem(char ***p, int len) { char **tmp; tmp = (char **)malloc(sizeof(char **)*len); for (int i = 0; i < len; i++) { tmp[i] = (char *)malloc(10); } *p = tmp; return 0; } int sortarry(char **p1, int len1, char(*p2)[10], int len2, char **p3, int len3) { int i = 0, j = 0, tmp = 0; for (int i = 0; i < len1; i++) { strcpy(p3[i], p1[i]); } for (i=0,j=len1; j < len3; i++,j++) { strcpy(p3[j], p2[i]); } for (i = 0; i < len3; i++) { for (j = 0; j < len3 - i - 1; j++) { if (strcmp(p3[j], p3[j + 1]) < 0) { tmp = p3[j]; p3[j] = p3[j + 1]; p3[j + 1] = tmp; } } } return 0; } int print(char **p, int len) { for (int i = 0; i < len; i++) { printf("%s ", p[i]); } return 0; } int memfree(char ***p, int len) { if (p == NULL) { return; } if (*p == NULL) { return; } char **tmp = *p; for (int i = 0; i < len; i++) { if (tmp[i] != NULL) { free(tmp[i]); } } free(tmp); *tmp = NULL; return 0; } int main() { char *p1[] = { "aaa","ddddd","cccc","eeeee" }; int len1 = sizeof(p1)/sizeof(*p1); char p2[][10] = { "qfef","ggrgrg","rgrggrg","hhhhdd" }; int len2 = sizeof(p2) / sizeof(p2[0]); char **p3; int len3 = len1 + len2; int ret; ret = getmem(&p3, len3); if (ret != 0) { printf("err1"); } ret = sortarry(p1, len1, p2, len2, p3, len3); if (ret != 0) { printf("err2"); } print(p3, len3); memfree(&p3, len3); return 0; }
-
结构体拷贝会存在浅拷贝的问题,即使用系统给的浅拷贝操作,如果结构体中存在指针指向堆空间数据,拷贝只是将指针地址拷贝,指针指向的内存空间并不会拷贝,再释放内存时,会存在两次释放,第一次释放后再释放没存数据的内存会报错宕掉,解决办法是将指向内存的数据也拷贝一份
错误案例: #include <stdio.h> #include <stdlib.h> #include<string.h> typedef struct Teacher { char name[64]; char *nname; int age; }Teacher; int main() { Teacher t1,t2; t1.nname = (char *)malloc(20); t2.nname = (char *)malloc(20); strcpy(t1.name, "aaaaa"); strcpy(t1.nname, "aa"); t1.age = 33; t2 = t1; printf("%s,%s,%d", t2.name, t2.nname,t2.age); if (t1.nname != NULL) { free(t1.nname); } if (t2.nname != NULL) { free(t2.nname); } return 0; } 正确案例: #include <stdio.h> #include <stdlib.h> #include<string.h> typedef struct Teacher { char name[64]; char *nname; int age; }Teacher; int main() { Teacher t1,t2; t1.nname = (char *)malloc(20); strcpy(t1.name, "aaaaa"); strcpy(t1.nname, "aa"); t1.age = 33; t2 = t1; t2.nname = (char *)malloc(20); strcpy(t2.nname, t1.nname); printf("%s,%s,%d", t2.name, t2.nname,t2.age); if (t1.nname != NULL) { free(t1.nname); } if (t2.nname != NULL) { free(t2.nname); } return 0; }
-
结构体中套一级指针
#include <stdio.h> #include <stdlib.h> #include<string.h> typedef struct Teacher { char name[64]; char *nnmae; int age; }Teacher; int nnmsefree(Teacher *arry,int len) { for (int i = 0; i < len; i++) { if (arry[i].nnmae != NULL) { free(arry[i].nnmae); arry[i].nnmae = NULL; } } } int initarry(Teacher *arry, int len) { for (int i = 0; i < len; i++) { arry[i].age = i + 20; } strcpy(arry[0].name, "aaaa"); strcpy(arry[1].name, "abbba"); strcpy(arry[2].name, "accca"); for (int i = 0; i < len; i++) { arry[i].nnmae= (char *)malloc(20); } strcpy(arry[0].nnmae, "1111aaaa"); strcpy(arry[1].nnmae, "2222abbba"); strcpy(arry[2].nnmae, "333accca"); return 0; } int print(Teacher p) { printf("%s %s %d\n", p.name, p.nnmae, p.age); return 0; } int main() { Teacher arry[3]; int len = sizeof(arry) / sizeof(arry[1]); initarry(arry, len); for (int i = 0; i < len; i++) { print(arry[i]); } nnmsefree(arry,len); }
-
结构体中套二级指针
指针数组: #include <stdio.h> #include <stdlib.h> #include<string.h> typedef struct Teacher { char name[64]; char *nnmae; char *student[3]; int age; }Teacher; int nnmsefree(Teacher *arry, int len, int slen) { for (int i = 0; i < len; i++) { if (arry[i].nnmae != NULL) { free(arry[i].nnmae); arry[i].nnmae = NULL; } } for (int i = 0; i < len; i++) { for (int j = 0; j < slen; j++) { if (arry[i].student[j] != NULL) { free(arry[i].student[j]); } arry[i].student[j] = NULL; } } return 0; } int initarry(Teacher *arry, int len, int slen) { for (int i = 0; i < len; i++) { arry[i].nnmae = (char *)malloc(20); } for (int i = 0; i < len; i++) { for (int j = 0; j < slen; j++) { arry[i].student[j] = (char *)malloc(20); } } for (int i = 0; i < len; i++) { sprintf(arry[i].name, "%d%d%daaa", i, i, i); } for (int i = 0; i < len; i++) { sprintf(arry[i].nnmae, "%d%dname", i, i); } for (int i = 0; i < len; i++) { for (int j = 0; j < slen; j++) { sprintf(arry[i].student[j], "%d%d%daaaa", i, j, j); } } for (int i = 0; i < len; i++) { arry[i].age = i + 20; } return 0; } int print(Teacher p, int slen) { printf("%s %s %d ", p.name, p.nnmae, p.age); for (int i = 0; i < slen; i++) { printf("%s ", p.student[i]); } return 0; } int main() { Teacher arry[3]; int len = sizeof(arry) / sizeof(arry[1]); int slen = sizeof(arry[0].student) / sizeof(arry[0].student[0]); initarry(arry, len, slen); for (int i = 0; i < len; i++) { print(arry[i], slen); printf("\n"); } nnmsefree(arry, len, slen); } 二维数组: #include <stdio.h> #include <stdlib.h> #include<string.h> typedef struct Teacher { char name[64]; char *nnmae; char student[3][10]; int age; }Teacher; int nnmsefree(Teacher *arry, int len) { for (int i = 0; i < len; i++) { if (arry[i].nnmae != NULL) { free(arry[i].nnmae); arry[i].nnmae = NULL; } } return 0; } int initarry(Teacher *arry, int len, int slen) { for (int i = 0; i < len; i++) { arry[i].age = i + 20; } for (int i = 0; i < len; i++) { arry[i].nnmae = (char *)malloc(20); } for (int i = 0; i < len; i++) { sprintf(arry[i].nnmae, "%d%dname", i, i); } for (int i = 0; i < len; i++) { sprintf(arry[i].name, "%d%d%daaa", i, i, i); } for (int i = 0; i < len; i++) { for (int j = 0; j < slen; j++) { sprintf(arry[i].student[j], "%d%d%daaaa", i, j, j); } } return 0; } int print(Teacher p, int slen) { printf("%s %s %d ", p.name, p.nnmae, p.age); for (int i = 0; i < slen; i++) { printf("%s ", p.student[i]); } return 0; } int main() { Teacher arry[3]; int len = sizeof(arry) / sizeof(arry[1]); int slen = sizeof(arry[0].student) / sizeof(arry[0].student[0]); initarry(arry, len, slen); for (int i = 0; i < len; i++) { print(arry[i], slen); printf("\n"); } nnmsefree(arry, len); } 二级指针 #include <stdio.h> #include <stdlib.h> #include<string.h> typedef struct Teacher { char name[64]; char *nnmae; char **student; int age; }Teacher; int nnmsefree(Teacher *arry, int len, int slen) { for (int i = 0; i < len; i++) { if (arry[i].nnmae != NULL) { free(arry[i].nnmae); arry[i].nnmae = NULL; } } for (int i = 0; i < len; i++) { for (int j = 0; j < slen; j++) { if (arry[i].student[j] != NULL) { free(arry[i].student[j]); } arry[i].student[j] = NULL; } } for (int i = 0; i < len; i++) { if (arry[i].student != NULL) { free(arry[i].student); arry[i].student = NULL; } } return 0; } int initarry(Teacher *arry, int len, int slen) { for (int i = 0; i < len; i++) { arry[i].nnmae = (char *)malloc(20); } for (int i = 0; i < len; i++) { arry[i].student = (char **)malloc(sizeof(char *)*slen); } for (int i = 0; i < len; i++) { for (int j = 0; j < slen; j++) { arry[i].student[j] = (char *)malloc(20); } } for (int i = 0; i < len; i++) { sprintf(arry[i].name, "%d%d%daaa", i, i, i); } for (int i = 0; i < len; i++) { sprintf(arry[i].nnmae, "%d%dname", i, i); } for (int i = 0; i < len; i++) { for (int j = 0; j < slen; j++) { sprintf(arry[i].student[j], "%d%d%daaaa", i, j, j); } } for (int i = 0; i < len; i++) { arry[i].age = i + 20; } return 0; } int print(Teacher p, int slen) { printf("%s %s %d ", p.name, p.nnmae, p.age); for (int i = 0; i < slen; i++) { printf("%s ", p.student[i]); } return 0; } int main() { Teacher arry[3]; int len = sizeof(arry) / sizeof(arry[1]); int slen = 3; initarry(arry, len, slen); for (int i = 0; i < len; i++) { print(arry[i], slen); printf("\n"); } nnmsefree(arry, len, slen); }
-
求结构体中变量的偏移量
#include <stdio.h> #include <stdlib.h> #include<string.h> typedef struct Teacher { char name[64]; int age; }Teacher; int main() { Teacher *p = NULL; int len = 0; len = (int)&(p->age); printf("%d\n", len); return 0; }
-
可以通过偏移量找到结构体中变量的位置,一旦结构体定义,其内存分布确定,不要轻易改变结构体中变量的位置 ;
-
结构体中变量内存分布会存在内存对齐的问题,所以一般将占用内存大的变量写在前面;
-
文件读写api
fputc fgetc //按照字符读写文件 fputs fgets //按照字符串读写文件 fread fwrite //按照块读写文件 fprintf //按照格式化进行读写文件
-
打开文件方式
"r" // 打开,只读 "w" // 打开,文件指针指到头,只写 "a" // 打开,指向文件尾,在已存在文件中追加 "rb" // 打开一个二进制文件,只读 "wb" // 打开一个二进制文件,只写 "ab" // 打开一个二进制文件,进行追加 "r+" // 以读/写方式打开一个已存在的文件 "w+" // 以读/写方式建立一个新的文本文件 "a+" // 以读/写方式打开一个文件文件进行追加 "rb+" // 以读/写方式打开一个二进制文件 "wb+" // 以读/写方式建立一个新的二进制文件 "ab+" //以读/写方式打开一个二进制文件进行追加
-
fputc和fgetc
#include <stdio.h> #include <stdlib.h> #pragma warning(disable : 4996) int main() { FILE *fp = NULL; char *filename = "d:/test.txt"; char *s = "hello,world"; fp = fopen(filename, "r+"); if (fp == NULL) { printf("打开文件失败\n"); goto END; } printf("打开文件成功\n"); for (int i = 0; s[i] != '\0'; i++) { fputc(s[i], fp); } if (fp != NULL) { fclose(fp); } char tmpc; fp = fopen(filename, "r"); if (fp == NULL) { printf("打开文件失败\n"); goto END; } while (!feof(fp)) { tmpc = fgetc(fp); printf("%c", tmpc); } END:if (fp != NULL) { fclose(fp); } return 0; }
-
fputs和fgets
#include <stdio.h> #include <stdlib.h> #include <malloc.h> #pragma warning(disable : 4996) int main() { FILE *fp = NULL; char *filename = "d:/test.txt"; char *s[] = { "hello,world","hello","helloworld" }; fp = fopen(filename, "w+"); if (fp == NULL) { printf("打开文件失败\n"); goto END; } printf("打开文件成功\n"); for (int i = 0; i<sizeof(s) / sizeof(s[0]); i++) { fputs(s[i], fp); fprintf(fp, "\n"); } if (fp != NULL) { fclose(fp); } char buf[1024]; fp = fopen(filename, "r"); if (fp == NULL) { printf("打开文件失败\n"); goto END; } while (!feof(fp)) { fgets(buf, 1024, fp); printf("%s", buf); } printf("%s", buf); END:if (fp != NULL) { fclose(fp); } return 0; }
-
如果要清空文件内容,直接以w+方式打开,会以空文件覆盖原有文件,即会清空文件内容,不需要清空文件内容,则可以用r+方式打开;
-
写入换行等可以使用fprintf函数;
-
fwrite和fread
#include <stdio.h> #include <stdlib.h> #pragma warning(disable : 4996) typedef struct Teacher { char name[1024]; int age; }Teacher; int mainwrite() { Teacher arry[3]; FILE *fp = NULL; char *s = "d:/teacher.txt"; int myn; fp = fopen(s, "wb"); if (fp == NULL) { printf("新建文件失败\n"); } for (int i = 0; i < 3; i++) { sprintf(arry[i].name, "%d%d%d", i, 2 * i, 3 * i); } for (int i = 0; i < 3; i++) { myn = fwrite(&arry[i].name, sizeof(Teacher), 1, fp); } if (fp != NULL) { fclose(fp); } return 0; } int mainread() { Teacher tarry[3]; FILE *fp = NULL; char *s = "d:/teacher.txt"; int myn; fp = fopen(s, "rb+"); if (fp == NULL) { printf("打开文件失败\n"); } for (int i = 0; i < 3; i++) { myn = fread(&tarry[i].name, sizeof(Teacher), 1, fp); } for (int i = 0; i < 3; i++) { printf("%s ", tarry[i].name); } if (fp != NULL) { fclose(fp); } return 0; } int main() { mainwrite(); mainread(); return 0; }
-
配置文件读写案例
思想: 实现一个配置文件的读写 读:输入key值,以字符串形式打印在屏幕上; 写:输入key值和value值,将key值和value值以“key=value”形式写入config配置文件中,如果key值已存在,直接修改key=后面的value值,等同修改功能 修改:输入key值和value值,如果在文件中找到已有key,直接修改key对应的value,如果没有,则在文件末尾添加“key=value”(实现思想是先新建一个文件,一 行一行读取文件中的内容,写入新文件中,找到key后,将该行替换再写入,然后将剩余部分写入新文件,最后将新文件改名替换); //config.h #pragma once int Tgetconfig(); int Twriterconfig(); int Tmodify(); int readconfig(char *key, char *value, int *vlen); //main.c #include "config.h" #include <stdio.h> #include <stdlib.h> #pragma warning(disable : 4996) int main() { int select = 1; while (select) { printf("*************************** *****\n"); printf("* [1]写配置文件 [2]读配置文件*\n"); printf("* [3]修改配置文件 [0]退出系统 *\n"); printf("********************************\n"); printf("请输入选项\n"); scanf("%d", &select); if (!(select >= 0 && select <= 3)) { printf("输入有误,请重新输入\n"); rewind(stdin); continue; } switch (select) { case 1: Twriterconfig(); break; case 2: Tgetconfig(); break; case 3: Tmodify(); break; case 0: break; default: break; } } return 0; } //config.c #include "config.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #pragma warning(disable : 4996) int Tgetconfig() { int ret = 0; char key[128]; char value[1024]; int vlen = 0; printf("请输入key值\n"); scanf("%s", key); ret = readconfig(key, value, &vlen); if (ret != 0) { printf("读取错误\n"); return ret; } printf("%s\n", value); return ret; } int Twriterconfig() { int ret = 0; char key[128]; char value[1024]; int vlen = 0; printf("请输入要写入的key值\n"); rewind(stdin); scanf("%s", key); printf("请输入要写入的value值\n"); rewind(stdin); scanf("%s", &value); ret = writeconfig(key, value, &vlen); if (ret != 0) { printf("写入失败\n"); } return 0; } int Tmodify() { int ret = 0; char key[128]; char value[1024]; int vlen = 0; printf("请输入要要修改key的值\n"); rewind(stdin); scanf("%s", key); printf("请输入要修改的value值\n"); rewind(stdin); scanf("%s", &value); ret = writeconfig(key, value, &vlen); if (ret != 0) { printf("写入失败\n"); } return ret; } int readconfig(char *key, char *value, int *vlen) { if (key == NULL || value == NULL || vlen == NULL) { printf("读取错误\n"); return -1; } char tmpbuf[1024]; char *tmp1; char *tmp2; int tmplen; FILE *fp; char *s = "d:/config.txt"; fp = fopen(s, "r+"); if (fp == NULL) { printf("未找到配置文件打开失败\n"); return -1; } while (!feof(fp)) { fgets(tmpbuf, 1024, fp); tmp1 = strstr(tmpbuf, key); if (tmp1 == NULL) { continue; } tmp1 = strstr(tmpbuf, "="); if (tmp1 == NULL) { continue; } tmp1++; while (*tmp1==' ') { tmp1++; } tmp2 = tmpbuf; while (*tmp2 != '\n') { tmp2++; } tmp2--; tmplen = tmp2 - tmp1 + 1; *vlen = tmplen; strncpy(value, tmp1, tmplen); value[tmplen] = 0; if (fp != NULL) { fclose(fp); } return 0; } printf("未找到key的value\n"); if (fp != NULL) { fclose(fp); } return -1; } int writeconfig(char *key, char *value, int *vlen) { if (key == NULL || value == NULL || vlen == NULL) { printf("读取错误\n"); return -1; } char *s1 = "d:/config.txt"; char *s2 = "d:/config.txt"; char tmpbuf[1024]; char *tmp; char sel; FILE *fp1; FILE *fp2; fp1 = fopen(s1, "r+"); if (!(fp2 = fopen(s2, "a"))) { fp2 = fopen(s2, "w+"); fclose(fp2); } fp2 = fopen(s2, "a"); if (fp1 == NULL) { printf("未找到配置文件,是否创建配置文件,y/n\n"); rewind(stdin); scanf("%c", &sel); if (sel == 'y') { fp1 = fopen(s1, "w+"); } if (sel == 'n') { printf("取消创建配置文件\n"); return -1; } } while (!feof) { fgets(tmpbuf, 1024, fp1); tmp = strstr(tmpbuf, key); if (tmp == NULL) { fputs(tmpbuf, fp2); continue; } tmp = strstr(tmpbuf, "="); if (tmp == NULL) { fputs(tmpbuf, fp2); continue; } fprintf(fp2, "%s=%s\n", key, value); continue; } fprintf(fp2, "%s=%s\n", key, value); fclose(fp2); rename(s2,s1); return 0; }
-
文件加密解密案例
#include "des.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #pragma warning(disable:4996) int fileEnc(char *s1,char *s2) { int ret = 0; FILE *fp1 = NULL, *fp2 = NULL; unsigned char plain[4096]; int plainlen = 0; unsigned char cryptbuf[4096] = { 0 }; int cryptlen = 0; int tmplen; fp1 = fopen(s1, "rb"); if (fp1 == NULL) { goto END; } fp2 = fopen(s2, "wb"); if (fp2 == NULL) { goto END; } while (!feof(fp1)) { plainlen = fread(plain, 1, sizeof(plain), fp1); if (feof(fp1)) //读完数据以后,判断是否文件结束 { break; } //加密==4k的数据,和加密小于4k的函数不是同一个函数 ret = DesEnc_raw(plain, plainlen, cryptbuf, &cryptlen); if (ret != 0) { printf("func DesEnc() err:%d \n", ret); goto END; } tmplen = fwrite(cryptbuf, 1, cryptlen, fp2); if (tmplen != cryptlen) { ret = -3; printf("写密文文件失败,请检查是否磁盘已满\n"); goto END; } //if (plainlen == 4096) } //加密小于4k的数据 ret = DesEnc(plain, plainlen, cryptbuf, &cryptlen); if (ret != 0) { printf("func DesEnc() err:%d \n", ret); goto END; } tmplen = fwrite(cryptbuf, 1, cryptlen, fp2); if (cryptlen != tmplen) { ret = -3; printf("写小于4k文件密文失败,请检查是否磁盘已满\n"); goto END; } END: if (fp1 != NULL) { fclose(fp1); } if (fp2 != NULL) { fclose(fp2); } return 0; } int fileDec(char *s1, char *s2) { int ret = 0; FILE *fp1 = NULL, *fp2 = NULL; unsigned char plain[4096]; int plainlen = 0; unsigned char cryptbuf[4096] = { 0 }; int cryptlen = 0; int tmplen; fp1 = fopen(s1, "rb"); if (fp1 == NULL) { goto END; } fp2 = fopen(s2, "wb"); if (fp2 == NULL) { goto END; } while (!feof(fp1)) { cryptlen = fread(cryptbuf, 1, sizeof(cryptbuf), fp1); if (feof(fp1)) { break; } ret = DesDec_raw(cryptbuf, cryptlen, plain, &plainlen); if (ret != 0) { printf("func DesDec() err:%d \n", ret); goto END; } tmplen = fwrite(plain, 1, plainlen, fp2); if (tmplen != plainlen) { ret = -3; printf("解密写文文件失败,请检查是否磁盘已满\n"); goto END; } } ret = DesDec(cryptbuf, cryptlen, plain, &plainlen); if (ret != 0) { printf("func DesDec() err:%d \n", ret); goto END; } tmplen = fwrite(plain, 1, plainlen, fp2); if (plainlen != tmplen) { ret = -3; printf("写小于4k文件密文失败,请检查是否磁盘已满\n"); goto END; } END: if (fp1 != NULL) { fclose(fp1); } if (fp2 != NULL) { fclose(fp2); } return 0; } int main() { char *s1 = "d:/ddd.txt"; char *s2 = "d:/ttt"; char *s3 = "d:/xxx.txt"; fileEnc(s1, s2); //加密 fileDec(s2, s3); //解密 return 0; }
-
指针的用法,二次调用
int getContentLen(const char *filename, char *buf, int *len) { char *tmp = NULL; tmp = (char *)malloc(100*sizeof(char)); if (buf == NULL) { *len = 10; //第一次调用求长度 } else { strncpy(tmp, "aaaaaaaaaaaaaaaaaaaaaaaaaa", 10); *len = 10; } return 0; } void main() { //char buf[1024*20]; const char *filename = "c:/1.txt"; char *p = NULL; int len = 0; getContentLen01(filename, &p, &len); if (p != NULL) { free(p); p = NULL; } //第一次调用求长度 getContentLen(filename, NULL, &len); p = (char *)malloc(len);//可以在主函数分配内存 if (p == NULL) { return ; } //第二次调用求内容 getContentLen(filename, p, &len); if (p != NULL) { free(p); p = NULL; } printf("hello...\n"); system("pause"); return ; }
-
两套socket api
int socketclient_init(void **handle); int socketclient_send(void *handle,unsigned char *buf,int buflen); int socketclient_recv(void *handle,unsigned char *buf,int *buflen); int socketclient_destory(void *handle);
int socketclient_init(void **handle); int socketclient_send(void *handle,unsigned char *buf,int buflen); int socketclient_recv(void *handle,unsigned char **buf,int *buflen); int socketclient_destory(void **handle);
-
socket第一套api
//main.c #define _CRT_SECURE_NO_WARNINGS #include <stdlib.h> #include <string.h> #include <stdio.h> #include <string.h> #include "socketclientdll.h" int main() { int ret = 0; void *handle = NULL; unsigned char buf[128]; int buflen = 3; int outbuflen; unsigned char outbuf[128]; strcpy(buf, "dfsgdsgdggdg"); ret = cltSocketInit(&handle /*out*/); if (ret != 0) { printf("err\n"); } //客户端发报文 ret = cltSocketSend(handle /*in*/, buf /*in*/, buflen /*in*/); //客户端收报文 ret = cltSocketRev(handle /*in*/, outbuf /*in*/, &outbuflen /*in out*/); if (ret != 0) { printf("err\n"); } //客户端释放资源 int cltSocketDestory(void *handle/*in*/); return 0; } //socket.h #ifndef _INC_Demo01_H #define _INC_Demo01_H #ifdef __cplusplus extern "C" { #endif //------------------第一套api接口---Begin--------------------------------// //客户端初始化 获取handle上下 int cltSocketInit(void **handle /*out*/); //客户端发报文 int cltSocketSend(void *handle /*in*/, unsigned char *buf /*in*/, int buflen /*in*/); //客户端收报文 int cltSocketRev(void *handle /*in*/, unsigned char *buf /*in*/, int *buflen /*in out*/); //客户端释放资源 int cltSocketDestory(void *handle/*in*/); //------------------第一套api接口---End-----------------------------------// //------------------第二套api接口---Begin--------------------------------// int cltSocketInit2(void **handle); //客户端发报文 int cltSocketSend2(void *handle, unsigned char *buf, int buflen); //客户端收报文 int cltSocketRev2(void *handle, unsigned char **buf, int *buflen); int cltSocketRev2_Free(unsigned char **buf); //客户端释放资源 int cltSocketDestory2(void **handle); //------------------第二套api接口---End--------------------------------// #ifdef __cplusplus } #endif #endif /* _INC_Demo01_H */ //socket.c #define _CRT_SECURE_NO_WARNINGS #include <stdlib.h> #include <string.h> #include <stdio.h> #include <string.h> #include "socketclientdll.h" typedef struct _SCK_HANDLE { char version[64]; char ip[128]; int port; unsigned char *p; int plen; }SCK_HANDLE; int cltSocketInit(void **handle /*out*/) { int ret = 0; SCK_HANDLE *hdl = (SCK_HANDLE *)malloc(sizeof(SCK_HANDLE)); if (hdl == NULL) { ret = -1; return ret; } memset(hdl, 0, sizeof(SCK_HANDLE)); strcpy(hdl->ip, "192.168.6.254"); hdl->port = 8081; *handle = hdl; return ret; } //客户端发报文 int cltSocketSend(void *handle /*in*/, unsigned char *buf /*in*/, int buflen /*in*/) { int ret = 0; SCK_HANDLE *hdl = NULL; if (handle == NULL || buf == NULL) { ret = -1; printf("func cltSocketSend() err:%d\n (unsigned char *)malloc(buflen *sizeof(unsigned char)",ret); return ret; } hdl = (SCK_HANDLE *)handle; hdl->p = (unsigned char *)malloc(buflen * sizeof(unsigned char)); if (hdl->p == NULL) { ret = -2; printf("func cltSocketSend() err:%d\n (unsigned char *)malloc(buflen *sizeof(unsigned char)",ret); return ret; } memcpy(hdl->p, buf, buflen); hdl->plen = buflen; return 0; } //客户端收报文 int cltSocketRev(void *handle /*in*/, unsigned char *buf /*in*/, int *buflen /*in out*/) { int ret = 0; SCK_HANDLE *hdl = NULL; if (handle == NULL || buf == NULL || buflen == NULL) { ret = -1; printf("func cltSocketRev() err:%d\n (handle==NULL || buf==NULL)", ret); return ret; } hdl = (SCK_HANDLE *)handle; memcpy(buf, hdl->p, hdl->plen); *buflen = hdl->plen; return ret; } //客户端释放资源 int cltSocketDestory(void *handle/*in*/) { int ret = 0; SCK_HANDLE *hdl = NULL; if (handle == NULL) { ret = -1; printf("func cltSocketDestory() err:%d\n (handle==NULL || buf==NULL )", ret); return ret; } hdl = (SCK_HANDLE *)handle; if (hdl->p) { free(hdl->p); } free(hdl); return 0; }
-
socket第二套api
//main.c #define _CRT_SECURE_NO_WARNINGS #include <stdlib.h> #include <string.h> #include <stdio.h> #include <string.h> #include "socketclientdll.h" int main() { int ret = 0; void *handle = NULL; unsigned char buf[128]; int buflen = 3; int poutlen; unsigned char *pout = NULL; strcpy(buf, "dfsgdsgdggdg"); ret = cltSocketInit2(&handle); if (ret != 0) { printf("err\n"); } //客户端发报文 ret = cltSocketSend2(handle /*in*/, buf /*in*/, buflen /*in*/); //客户端收报文 ret = cltSocketRev2(handle /*in*/, &pout /*in*/, &poutlen /*in out*/); if (ret != 0) { printf("err\n"); } //客户端释放资源 cltSocketDestory2(&handle/*in*/); return 0; } //socket.h //written by wangbaoming1999@163.com //20140323 23:10 /* 下面定义了一套socket客户端发送报文接受报文的api接口 请写出这套接口api的调用方法 */ #ifndef _INC_Demo01_H #define _INC_Demo01_H #ifdef __cplusplus extern "C" { #endif //------------------第一套api接口---Begin--------------------------------// //客户端初始化 获取handle上下 int cltSocketInit(void **handle /*out*/); //客户端发报文 int cltSocketSend(void *handle /*in*/, unsigned char *buf /*in*/, int buflen /*in*/); //客户端收报文 int cltSocketRev(void *handle /*in*/, unsigned char *buf /*in*/, int *buflen /*in out*/); //客户端释放资源 int cltSocketDestory(void *handle/*in*/); //------------------第一套api接口---End-----------------------------------// //------------------第二套api接口---Begin--------------------------------// int cltSocketInit2(void **handle); //客户端发报文 int cltSocketSend2(void *handle, unsigned char *buf, int buflen); //客户端收报文 int cltSocketRev2(void *handle, unsigned char **buf, int *buflen); int cltSocketRev2_Free(unsigned char **buf); //客户端释放资源 int cltSocketDestory2(void **handle); //------------------第二套api接口---End--------------------------------// #ifdef __cplusplus } #endif #endif /* _INC_Demo01_H */ //socket.c #define _CRT_SECURE_NO_WARNINGS #include <stdlib.h> #include <string.h> #include <stdio.h> #include <string.h> #include "socketclientdll.h" typedef struct _SCK_HANDLE { char version[64]; char ip[128]; int port; unsigned char *p; int plen; }SCK_HANDLE; int cltSocketInit(void **handle /*out*/) { int ret = 0; SCK_HANDLE *hdl = (SCK_HANDLE *)malloc(sizeof(SCK_HANDLE)); if (hdl == NULL) { ret = -1; return ret; } memset(hdl, 0, sizeof(SCK_HANDLE)); strcpy(hdl->ip, "192.168.6.254"); hdl->port = 8081; *handle = hdl; return ret; } //客户端发报文 int cltSocketSend(void *handle /*in*/, unsigned char *buf /*in*/, int buflen /*in*/) { int ret = 0; SCK_HANDLE *hdl = NULL; if (handle == NULL || buf == NULL) { ret = -1; printf("func cltSocketSend() err:%d\n (unsigned char *)malloc(buflen *sizeof(unsigned char)", ret); return ret; } hdl = (SCK_HANDLE *)handle; hdl->p = (unsigned char *)malloc(buflen * sizeof(unsigned char)); if (hdl->p == NULL) { ret = -2; printf("func cltSocketSend() err:%d\n (unsigned char *)malloc(buflen *sizeof(unsigned char)", ret); return ret; } memcpy(hdl->p, buf, buflen); hdl->plen = buflen; return 0; } int cltSocketInit2(void **handle) { return cltSocketInit(handle); } //客户端发报文 int cltSocketSend2(void *handle, unsigned char *buf, int buflen) { return cltSocketSend(handle, buf, buflen); } //客户端收报文 int cltSocketRev2(void *handle, unsigned char **buf, int *buflen) { int ret = 0; SCK_HANDLE *hdl = NULL; unsigned char *tmp = NULL; if (handle == NULL || buf == NULL || buflen == NULL) { ret = -1; printf("func cltSocketRev2() err:%d\n (handle==NULL || buf==NULL", ret); return ret; } hdl = (SCK_HANDLE *)handle; tmp = (unsigned char *)malloc(hdl->plen); if (tmp == NULL) { ret = -2; printf("func cltSocketRev2() err:%d\n (handle==NULL || buf==NULL", ret); return ret; } memcpy(tmp, hdl->p, hdl->plen); *buflen = hdl->plen; *buf = tmp; //间接赋值 return ret; } int cltSocketRev2_Free(unsigned char **buf) { if (buf == NULL) { return -1; } if (*buf != NULL) { free(*buf); } *buf = NULL; //*实参的地址 去间接的修改实参的值 重新初始化NULL return 0; } //客户端释放资源 int cltSocketDestory2(void **handle) { SCK_HANDLE *tmp = NULL; if (handle == NULL) { return -1; } tmp = *handle; if (tmp != NULL) { if (tmp->p) { free(tmp->p); tmp->p = NULL; } free(tmp); } *handle = NULL; //*实参的地址 去间接的修改实参的值 重新初始化NULL return 0; }
-
VS中生成动态库,新建dll工程,编写函数,在每个函数前加__declspec(dllexport),编译生成dll文件和lib文件,将dll文件和lib文件放入需要使用的工程文件中,包含头文件,在属性设置链接器的宏包含.lib文件就可以使用动态库了;
-
动态库日志功能的集成,在动态库工程中加入日志头文件和实现代码,调用日志函数;
-
检测内存泄漏的工具
## memwatch: ### 应用环境: Win/Linux ### 编程语言: C/C++ 不建议使用在C++上 ### 使用方法: Win VS:将memwatch.h,memwatch.c加入到项目,代码包含memwatch.h头文件,项目->属性->C/C++->预处理器->预处理器定义设置添加宏DMEMWATCH和DMW_STDIO Linux:加入memwatch.h,编译时加上-DMEMWATCH -DMW_STDIO及memwatch.c ### 结果输出: 输出文件名称为memwatch.log,在程序执行期间,错误提示都会显示在stdout上 ### 设计思路: 将malloc/realloc/calloc/strdup/free等重定义为mwMalloc(sz, **FILE**, **LINE**)等,内部维护一个操作链表 ### 优缺点: 能检测双重释放(double-free)、错误释放(erroneous free)、内存泄漏(unfreed memory)、溢出(Overflow)、下溢(Underflow)等 ### 如何获取: http://memwatch.sourceforge.net/ ## debug_new ### 应用环境: Linux/Windows ### 编程语言: C++ ### 使用方法: 包含头文件debug_new.h,链接debug_new.cpp ### 结果输出: 控制台console ### 设计思路: 通过重载new和delete操作符来捕获内存申请/释放请求,并在程序内部维护一个全局静态变量的哈希链表。在new操作符中,不仅仅分配用户所要求的内存,而是在为每次分配的内存都添加一个头部,存储着此次分配的位置信息和链表指针,new返回的是分配的这块内存加上头部偏移后的值,而在之前已经将此返回值作了HASH计算并添加到HASH链表中了。delete的时候先根据要释放的指针地址做HASH计算,然后再遍历数组HASH值处的链表进行查找,如果找到则将该节点移除,未找到就abort。这样在程序结束之后,通过检查此数组中是否还有未释放的内存块来确定是否有内存泄露。 ### 优缺点: 跨平台,仅用于C++程序 ### 如何获取: http://www.ibm.com/developerworks/cn/linux/l-mleak2/index.html
-
对于动态库编写和调用,在哪里分配内存就在哪里释放,不然会出现各种各样的问题;
C语言复习
于 2020-09-25 14:58:02 首次发布