​ 回炉重造, 还是通过gdb调试一下,理解的比较好, 多写代码多调试!

指针与地址初探

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

void main(){
int x=1,y=2,z[10];
int *ip;
ip = &x;
z[0] = 1;
z[1] = 2;
z[8] = 5;
y = *ip;
*ip = 0;
ip = &z[0];

x = 1;

}

gcc -g main.c

​ ip是一个指针,在第六行,把x的地址赋给了指针,所以ip的值就是x的地址,ip本身就是一个值,也有自己的地址,

image-20230927170316918

​ 感觉这种未初始化的数组或许能做信息泄露?

image-20230927170602436

指针与函数参数

​ 函数传递指针,实现赋值. 主要是getint函数,获取任意值,然后转换成数值,int类型的数值 而不是char类型的数值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <ctype.h>

#include <stdio.h>


int getch(void);
void ungetch(int);

//将输入的字符流分解成整数
int getint(int *pn)
{
int c,sign;

while(isspace(c = getch())) ;
if (!isdigit(c) && c !=EOF && c!='+' && c !='-'){ //输入不是数字、结束符号,+-符号时返回0
ungetch(c);
return 0;
}

sign = (c == '-') ? -1:1; //获取符号
if (c=='+' || c =='-')
c = getch();
/*
原来设想的数可能是 +1 -2这种,所以要先检测一下符号

这个循环的意思是, 假如输入了 12345 这种(不是一位的数值), 一个一个读取,然后前一位 乘10,逐级递增,这个没问题,但 c - 0是什么?

c的话,本身是 字符 ,这里是减去0 的ascii码,就 取得了 整数
*/

for (*pn=0; isdigit(c); c=getch())
*pn = 10 * *pn + (c - '0');
*pn *= sign;
if (c != EOF) //先缓存一下
ungetch(c);
return c;
}

#define SIZE 10
void main()
{

int n, array[SIZE],getint(int *);
// 实现给一个整形数组 赋值
for (n=0; n < SIZE && getint(&array[n]) != EOF; n++)
;
for (n=0; n < SIZE; n++) //打印
printf("the %d number is %d\n",n,array[n]);

}

#define BUFSIZE 100

char buf[BUFSIZE];
int bufp =0;

int getch(void)
{
return (bufp > 0 ) ? buf[--bufp] : getchar();
}

void ungetch(int c)
{
if (bufp >= BUFSIZE)
printf("ungetch: too many characters\n");
else
buf[bufp++] = c;
}

关于 c-‘0’的问题

1
2
  for (*pn=0; isdigit(c); c=getch()) 
*pn = 10 * *pn + (c - '0');

​ 输入12345, ascii的话就是49 50 51 52 53
问题在于, 对于getchar()得到的数值,会是ascii码, 而直接赋值得到的是内存中数值,所以需要这么一个转换

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>

void main(){

int a=1;
char b = 1;
int c;
c = getchar();

int d;
d = getchar();

}

​ 虽然但是,a和b还是不一样的,a占用4个字节,b占用一个字节

​ 虽然但是,a和b还是不一样的,a占用4个字节,b占用一个字节

strlen 注意, 参数处的 *s 和 for循环里的 *s 是两个含义, 一个是代表定义指针, 一个是取指针指向的地址的值,差了两层

1
2
3
4
5
6
7
8
int strlen(char *s)
{
int n;

for (n=0; *s!='\0'; s++)
n++;
return n;
}

版本2, 数组的尾元素+1 (结束\0) 减头元素就是长度,

1
2
3
4
5
6
7
int strlen(char *s)
{
char *p = s;
while(*p != '\0')
p++;
return p-s;
}

理解地址算数运算: 一个简单的存储分配程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <stdio.h>
#include <string.h>
#define ALLOCSIZE 10000

static char allocbuf[ALLOCSIZE];

static char *allocp = allocbuf;

char *alloc(int n)
{
if (allocbuf + ALLOCSIZE - allocp >= n){ //有足够的空闲空间
allocp += n;
return allocp - n; //分配前的指针p
}else{
return 0;
}

}


void afree(char *p) //释放p指向的存储区
{
if (p >= allocbuf && p < allocbuf + ALLOCSIZE)
allocp = p;

}

void main()
{
char *data1,*data2;
int a;
char src[50] = "hello wolrd";
char src2[50] = "this is the second mem region";
data1 = alloc(100);
memcpy(data1,src,strlen(src)+1);

data2 = alloc(200);
memcpy(data2,src2,strlen(src2)+1);

a= 1;
}

strcpy的实现

实现把指针t指向的字符串复制到指针s指向的位置, 但是不能用s=t,因为这个只是拷贝了指针,并没有复制字符串,

数组方法实现:

1
2
3
4
5
6
7
void strcpy(char *s, char *t)
{
int i;
i = 0;
while((s[i] = t[i]) != '\0')
i++;
}

指针方法实现:

1
2
3
4
5
6
7
8
void strcpy(char *s, char *t)
{
while((*s = *t) != '\0')
{
s++;
t++;
}
}

经验丰富的程序员更喜欢编写成一下形式:

1
2
3
4
5
void strcpy(char *s,char *t)
{
while ((*s++ = *t++) != '\0')
;
}

还可以进一步缩写,因为和0比较是多余的,while循环的条件本身就需要非0

1
2
3
4
5
void strcpy(char *s,char *t)
{
while (*s++ = *t++)
;
}

strcmp的实现

1
2
3
4
5
6
7
8
int strcmp(char *s,char *t)
{
int i;
for (i=0;s[i] == t[i];i++)
if(s[i] == '\0')
return 0
return s[i] - t[i];
}

用指针来实现

1
2
3
4
5
6
7
int strcmp(char *s,char *t)
{
for(;*s == *t;s++,t++)
if (*s == '\0')
return 0
return *s - *t;
}

指针数组排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <stdio.h>
#include <string.h>

#define MAXLINES 5000

char *lineptr[MAXLINES];

int readlines(char *lineptr[],int nlines);
void writelines(char *lineptr[],int nlines);

void main()
{
int nlines;

if ((nlines = readlines(lineptr,MAXLINES)) >=0 ){
qsort(lineptr,0,nlines-1);
writelines(lineptr,nlines);
return 0;
}else{
printf("error: input too big to sort\n");
return 1;
}
}


#define MAXLEN 1000
int getline(char *,int);
char *alloc(int);

int readline(char *lineptr[],int maxlines)
{
int len, nlines;
char *p,line[MAXLEN];
nlines = 0;
while((len = getline(line,MAXLEN)) > 0 )
{
if (nlines > maxlines || (p = alloc(len)) == NULL)
return -1;
else{
line[len-1] = '\0';//删除换行符
strcpy(p,line);
lineptr[nlines++] = p;
}
}
return nlines;
}

void writelines(char *lineptr[],int nlines)
{
int i;
for(i = 0;i<nlines;i++)
printf("%s\n",lineptr[i]);
}

void qsort(char *v[], int left,int right)
{
int i,last;
void swap(char *v[],int i, int j);
if (left >= right)
return;
swap(v,left,(left+right)/2);
last = left;
for(i = left+1; i<= right; i++)
if (strcmp(v[i],v[left]) < 0 )
swap(v,++last,i);
swap(v,left,last);
qsort(v,left,last-1);
qsort(v,last+1,right);
}

void swap(char *v[],int i,int j)
{
char *temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}

基础快速排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <stdio.h>


void swap(int v[],int i,int j);
void qsort(int v[],int left,int right);

void main()
{
int i;
int v[11] = {3,2,9,2,3,7,8,1,6,8,4};
qsort(v,0,10);
for(i=0;i<11;i++)
printf("%d,",v[i]);
}


void swap(int v[],int i,int j)
{
int temp;

temp = v[i];
v[i] = v[j];
v[j] = temp;
}

// 3,2,9,2,3,7,8,1,6,8,4
// 以递增顺序对v[left]到v[right]进行排序
void qsort(int v[],int left,int right)
{
int i,last;
void swap(int v[],int i,int j);

if (left >= right) return;
swap(v,left, (left+right)/2);
last = left;
for (i = left+1;i<=right;i++)
if (v[i] < v[left])
swap(v,++last,i);
swap(v,left,last);
//qsort(v, left, last-1);
//qsort(v,last+1,right);
}


举例
3,2,9,2,3,7,8,1,6,8,4
qsort(v,0,10)
第一次排序后
4,2,2,3,3,1,6,7,8,8,9
第一次把中间的7放到开头,然后对比,依次把小于它的往前放,放到last+1的位置
7,2,9,2,3,3,8,1,6,8,4
7,2,2,9,3,3,8,1,6,8,4
7,2,2,3,9,3,8,1,6,8,4
7,2,2,3,3,9,8,1,6,8,4
7,2,2,3,3,1,8,9,6,8,4
7,2,2,3,3,1,6,9,8,8,4
7,2,2,3,3,1,6,4,8,8,9 //此时last在4这个位置,肯定也是比它小的,而且是最后一个,此时再swap就可以了

多维数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <stdio.h>

int day_of_year(int year, int month,int day);
void month_day(int year,int yearday,int *pmonth,int *pday);

void main()
{
int choice;
int year,month,day;
int dayofyear;
int dayofmonth;
printf("请输入选项\n1.将某年某月某日的日期表示形式转换成某年第几天的形式\n2.将某年中第几天的日期表示形式转换为某月某日\n");
scanf("%d",&choice);
switch(choice){
case 1:
printf("请输入年月日,空格隔开\n");
scanf("%d %d %d",&year,&month,&day);
dayofyear = day_of_year(year,month,day);
printf("%d年%d月%d日是%d年第%d天\n",year,month,day,year,dayofyear);
break;
case 2:
printf("请输入年份和天数,空格隔开\n");
scanf("%d %d",&year,&day);
month_day(year,day,&month,&dayofmonth);
printf("%d年第%d天是%d年%d月%d号",year,day,year,month,dayofmonth);
break;
}
}

static char daytab[2][13]={
{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31}
};

//将某年某月某日的日期表示形式转换成某年第几天的形式
int day_of_year(int year, int month,int day)
{
int i,leap;

leap = year%4 == 0 && year%100 !=0 || year % 400 ==0;
for(i=1;i< month;i++)
day+= daytab[leap][i];
return day;
}

//将某年中第几天的日期表示形式转换为某月某日
void month_day(int year,int yearday,int *pmonth,int *pday)
{
int i,leap;

leap = year%4 == 0 && year%100 !=0 || year % 400 ==0;
for (i=1;yearday > daytab[leap][i];i++)
yearday -= daytab[leap][i];
*pmonth = i;
*pday = yearday;

}

命令行参数 echo

第一个版本将argv看成一个字符指针数组

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>

int main(int argc,char *argv[])
{
int i;

for (i=0; i<argc; i++)
printf("%s%s",argv[i],(i < argc-1) ? " ": "");
printf("\n");
return 0;
}

因为argv是一个指向指针数组的指针,所以,可以通过指针而非数组下标的方式处理命令行参数.

第二个版本是在对argv进行自增运算、对argc进行自减运算的基础上实现的(argv是一个指向char类型的指针的指针)

1
2
3
4
5
6
7
8
9
#include <stdio.h>

int main(int argc,char *argv[])
{
while( --argc > 0)
printf("%s%s",*++argv,(argc > 1)? " ":"");
printf("\n");
return 0;
}

模式查找程序

4.1节 内置了查找模式

​ 将输入中包含特定“模式”或字符串的各行打印出来(grep的特例相当于)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <stdio.h>
#define MAXLINE 1000

int getline1(char line[],int max);
int strindex(char source[],char searchfor[]);


char pattern[] = "tang";

int main()
{
char line[MAXLINE];
int found = 0;
while (getline1(line,MAXLINE) > 0 )
if(strindex(line,pattern) >= 0 ){
printf("%s",line);
found++;
}
return found;
}
//将行保存到s中,并返回该行的长度
int getline1(char s[],int lim)
{
int c,i;
i = 0;
while(--lim >0 && (c=getchar()) != EOF && c != '\n')
s[i++] = c;
if(c=='\n')
s[i++] = c;
s[i] = '\0';
return i;
}

// 返回t在s中的位置,如果没找到返回-1
int strindex(char s[],char t[])
{
int i,j,k;

for (i=0; s[i] !='\0';i++){
for(j = i,k=0; t[k]!='\0' && s[j]==t[k];j++,k++)
;
if (k > 0 && t[k] == '\0')
return i;
}
return -1;
}

5.10 增强版 实现find功能,打印与第一个参数指定的模式匹配的行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>
#include <string.h>
#define MAXLINE 1000

int getline1(char *line, int max);

//
int main(int argc,char *argv[])
{
char line[MAXLINE];
int found = 0;
if (argc !=2 )
printf("Usage: find pattern\n");
else
while(getline1(line,MAXLINE) > 0)
if (strstr(line,argv[1]) != NULL){
printf("%s",line);
found++;
}
return found;
}

int getline1(char s[],int lim)
{
int c,i;
i = 0;
while(--lim >0 && (c=getchar()) != EOF && c != '\n')
s[i++] = c;
if(c=='\n')
s[i++] = c;
s[i] = '\0';
return i;
}


再次改进

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <stdio.h>
#include <string.h>
#define MAXLINE 1000

int getline1(char *line, int max);

//
int main(int argc,char *argv[])
{
char line[MAXLINE];
long lineno = 0;
int c,except = 0, number = 0, found =0;

while(--argc > 0 && (*++argv)[0] == '-')
while(c = *++argv[0]) //这里的++...........是那个意思?
switch(c){
case 'x':
except = 1;
break;
case 'n':
number = 1;
break;
default:
printf("find: illegal option %c\n",c);
argc = 0;
found = -1;
break;
}

if (argc !=1 )
printf("Usage: find -x -n pattern\n");
else
while(getline1(line,MAXLINE) > 0){
lineno++;
if ((strstr(line,*argv) != NULL)!= except){
if(number)
printf("%ld:",lineno);
printf("%s",line);
found++;
}
}
return found;
}

int getline1(char s[],int lim)
{
int c,i;
i = 0;
while(--lim >0 && (c=getchar()) != EOF && c != '\n')
s[i++] = c;
if(c=='\n')
s[i++] = c;
s[i] = '\0';
return i;
}


函数指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>

#define ALLOCSIZE 10000
#define MAXLINES 5000
#define MAXLEN 1000

char *lineptr[MAXLINES];

int readlines(char *lineptr[],int maxlines);
void writelines(char *lineptr[],int nlines);
void qsort1(void *v[], int left,int right,int (*comp)(void *,void *));
int numcmp(char *,char *);
int getline1(char *line, int max);
char *alloc(int n);


//对输入的文本进行排序
int main(int argc,char *argv[])
{
int nlines; //读入的输入行数
int numeric = 0; //若进行数值排序,则 numberic的值为1

if(argc > 1 && strcmp(argv[1],"-n") == 0)
numeric = 1;
if ((nlines = readlines(lineptr,MAXLINES)) >= 0){
qsort1((void **)lineptr, 0, nlines -1, (int (*)(void*,void*))(numeric ? numcmp:strcmp));
writelines(lineptr, nlines);
return 0;
}else{
printf("input too big to sort\n");
return 1;
}

}

int readlines(char *lineptr[],int maxlines)
{
int len, nlines;
char *p,line[MAXLEN];
nlines = 0;
while((len = getline1(line,MAXLEN)) > 0 )
{
if (nlines > maxlines || (p = alloc(len)) == NULL)
return -1;
else{
line[len-1] = '\0';//删除换行符
strcpy(p,line);
lineptr[nlines++] = p;
}
}
return nlines;
}

void writelines(char *lineptr[],int nlines)
{
int i;
for(i = 0;i<nlines;i++)
printf("%s\n",lineptr[i]);
}

void qsort1(void *v[], int left,int right,int (*comp)(void *,void *))
{
int i,last;
void swap(void *v[],int i, int j);
if (left >= right)
return;
swap(v,left,(left+right)/2);
last = left;
for(i = left+1; i<= right; i++)
if ((*comp)(v[i],v[left]) < 0 )
swap(v,++last,i);
swap(v,left,last);
qsort1(v,left,last-1,comp);
qsort1(v,last+1,right,comp);
}

int numcmp(char *s1, char *s2)
{
double v1,v2;

v1 = atof(s1);
v2 = atof(s2);
if (v1<v2)
return -1;
else if (v1 > v2)
return 1;
else
return 0;
}

void swap(void *v[],int i,int j)
{
char *temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}


int getline1(char s[],int lim)
{
int c,i;
i = 0;
while(--lim >0 && (c=getchar()) != EOF && c != '\n')
s[i++] = c;
if(c=='\n')
s[i++] = c;
s[i] = '\0';
return i;
}



static char allocbuf[ALLOCSIZE];

static char *allocp = allocbuf;

char *alloc(int n)
{
if (allocbuf + ALLOCSIZE - allocp >= n){ //有足够的空闲空间
allocp += n;
return allocp - n; //分配前的指针p
}else{
return 0;
}

}

(void **)是啥, 将指针数组转换成 指向指针数组的指针类型

复杂声明

程序dcl是啥

1
2
3
4
char **argv
argv: pointer to pointer to char
int (*daytab)[13]
daytab: pointer to array[13] of int

q

能不能用gdb显示变量信息呢,结构信息等,比如char和int的区别

EOF的话,包括哪些