scanf输入问题-输入缓冲区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

int main(void)
{

char ch;
int i=0;
int b;
b=scanf("%c",&ch);
while(b == 1)
{
printf("%d",i++);
printf("?");
b=scanf("%c",&ch);\
}
printf("Done\n");
return 0;
}
//会得到

​```c
a//输入a
0?a1?

原因是因为scanf()函数会把回车、空格、Tab或一些不合理输入的字符当作此次输入的结束标志,它不会把这些字符输入到想要保存此次输入数据的变量中,而是把这些字符遗留在了输入缓冲区,那么,当下一次想要从标准输入中读取一个字符时,这个遗留的字符就正好充当了此次的输入字符。

程序在输入a后输入了回车来结束此次输入,那么回车就遗留在了输入缓冲区,当需要给c输入字符时,它自动的充当了输入的字符,因此,程序没有给我们输入c的字符的机会。

C语言为了解决这种问题,为我们提供了一种很方便的清空输入缓冲区的方式—->>fflush()函数,fflush(stdin)它会把残留在输入缓冲区里的所有数据清空。头文件为stdio.h

或者使用

1
2
while ((ch = getchar()) != '\n')
continue;//跳过该行剩下的内容。

C primer plus提供的输入程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
char s_gets(char *st, int n)
{
char * ret_val;
int i = 0;

ret_val = fgets( st, n, stdin);
if(ret_val)
{
while(st[i]!= '\n' &&st[i]!= '\0')
i++;
if(st[i] == '\n')
st[i] == '\0';
else
while(getchar()!='\n')
continue;
}
return ret_val;

}

错题:位运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
int fun(int i);

int main()
{
printf("%d\n",fun(2017));
return 0;
}

int fun(int i)
{
int cnt = 0;
while(i)
{
cnt++;
i = i&(i-1);//i = i & (i-1),统计i二进制中有多少个1
} //i = i | (i+1),统计i二进制中有多少个0
return cnt;
}

指针数组

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
int main()
{
char *str[3] ={"stra", "strb", "strc"};
char *p =str[0];
int i = 0;
while(i < 3)
{
printf("%s ",p++);
i++;
}
return 0;
}

char指针数组可以指向多个字符,直到遇到空为止。p本来指向第一个字符,但是因为是指针,所以要遇到空为止才算读完第一个‘字符’,后面p+1指向第二个字符,同样也是遇到空为止,同理p+2 所以输出为stra,tra,ra。注意循环里面是p++所以从p0开始打印啦。

指针和自增自减的优先级

1
2
3
4
5
6
7
8
9
10
11
12
int arr[] = { 1, 3668, 5, 7, 9};
printf("%d\n", *p++ );//拿到arr[0]的值1
printf("%d\n", *p++ ); //上条语句结束后指针往后移动了一下,
//指到到arr[1],然后又++,因为是后++,
//所以解得是arr[1]的值3668
printf("%d\n", (*p)++ );//拿到上个++指向了arr[2],
//因为加了括号,所以先解值为5,然后++,
//把结果丢给了下语句。
printf("%d\n", (*p)++ );//括号优先级高,先解值,指针未移动,
//还指向着arr[2],拿到上个printf丢下来的值5+1=6,
//故解值为6,然6++,语句执行结束把6++结果丢给下一条语句。

extern关键字

在C语言中,修饰符extern用在变量或者函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用”。extern声明不是定义,即不分配存储空间。

extern”C” 作用

C++语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成一个中间的函数名称,而C语言则不会,因此会造成链接时无法找到对应函数的情况,此时C函数就需要用extern “C”进行链接指定,这告诉编译器,请保持我的名称,不要给我生成用于链接的中间函数名。

1
2
3
4
5
6
7
8
9
#ifdef __cplusplus  
extern "C" {
#endif

//把所有函数声明放在这。

#ifdef __cplusplus
}
#endif

#if…#endif的作用

1
2
3
4
5
6
#if 1
code 执行代码
#endif
#if 0
code 屏蔽代码
#endif

同样可以“屏蔽”一段代码,你想把说明文字写在里面也可以,这些和“/* */”都一样,但不一样的是:第一它允许嵌套(层数上限由预处理器决定)、第二你随时可以把“#if 0”改成“#if 1”来取消对某段代码的“屏蔽。

结构体大小

结构体计算遵循对齐原则:

1)结构体变量首地址能够背其最宽基本类型成员的大小所整除;

2)结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有比那一起会在成员之间加上填充字节;

3)结构体的总大小为结构体最宽基本类型成员的大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。

偏移量指的是结构体变量中成员的地址和结构体变量地址的差。结构体大小等于最后一个成员的偏移量加上最后一个成员的大小。

eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<stdio.h>
struct person
{
char fname; //第一个成员偏移量为0
int age; //第二个成员偏移量等于0+第一个的大小1=1但是得是第二个成员大小的整数倍所以是4
double time;//第三个成员偏移量等于4+第二个的大小4=8但是得是第三个成员大小的整数倍所以是8
float old; //第四个成员偏移量等于8+第三个的大小8=16但是得是第四个成员大小的整数倍所以是16
}; //16+4=20但是得是所有的整数倍所以是24;
int main()
{
struct person student;
printf("%ld", sizeof(student));

return 0;
}

内存对齐是什么

一文轻松理解内存对齐_程序员_C语言与CPP编程

为什么要用malloc何时用

1
void *malloc(unsigned int num_bytes);	//分配num_bytes字节的内存块

返回值是void指针,void* 表示未确定类型的指针,void *可以指向任何类型的数据,更明确的说是指申请内存空间时还不知道用户是用这段空间来存储什么类型的数据(比如是char还是int或者其他数据类型),可以通过类型强制转化转化为其他任意类型指针。如果分配成功则返回指向被分配内存的指针(此存储区中的初始值不确定),否则返回空指针NULL。

malloc()是动态内存分配函数,用来向系统请求分配内存空间。当无法知道内存具体的位置时,想要绑定真正的内存空间,就要用到malloc()函数。因为malloc只管分配内存空间,并不能对分配的空间进行初始化,所以申请到的内存中的值是随机的,经常会使用memset()进行置0操作后再使用。

与其配套的是free(),当申请到的空间不再使用时,要用free()函数将内存空间释放掉,这样可以提高资源利用率,最重要的是—-就是因为它可以申请内存空间,然后根据需要进行释放,才被称为“动态内存分配”!

1
2
3
4
5
6
7
8
9
10
int *p;
  p = (int*)malloc(sizeof(int) * 128);
    //分配128个整型存储单元,并将这128个连续的整型存储单元的首地址存储到指针变量p中
  double *pd = (double*)malloc(sizeof(double) * 12);  
    //分配12个double型存储单元,并将首地址存储到指针变量pd中
  free(p);
  free(pd);
  p = NULL;
  pd = NULL;  
  指针用完赋值NULL是一个很好的习惯。

C语言中的联合

联合是在同一个内存空间中存储不同的数据类型(不能同时存在多个类型)。例如:

1
2
3
4
5
6
union hold
{
int digit;
double bigf1;
char letter;
};

以上声明的结构只能存储整型或浮点型或者字符型的变量,不能同时存在。

初始化联合

有三种方法初始化联合:
1、把一个联合初始化为另一个同类型的联合

2、初始化联合的第一个成员

3、使用指定初始化器(C99标准)

1
2
3
4
5
6
7
union car first_car;
first_car.car_name='A';
union car sec_car=first_car; //把一个联合初始化为另一个同类型的联合

union car car_a={'B'};     //初始化联合的第一个成员

union car car_b={.car_num=2}; //使用指定初始化器来初始化联合car_b

用指针访问联合时候也是用->运算符。

1
2
pu = &fit;
x = pu ->digit;

传递结构体数组地址

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
#include<stdio.h>
#include<string.h>
char * s_gets(char * st, int n);
void menu(void);
#define LIM 20
#define SIZE 81
#define MAXTITL 40
#define MAXAUTL 40
#define MAXBKS 100

struct book
{
char title [MAXTITL];
char author[MAXAUTL];
float value;
};
int srt( struct book prt[], int n);
int change(struct book pt[], int m);

int main(void)
{
struct book library[MAXBKS];
struct book *pst;
int i;
int t;
pst = &library[0];
menu();
for( i = 0; i < MAXBKS; i++ )
{
if(s_gets(library[i].title, MAXTITL) == NULL || library[i].title[0] == '\0')
break;
printf("输入作者\n");
s_gets(library[i].author, MAXAUTL);
printf("输入价格\n");
scanf("%f", &library[i].value);
printf("输入书名\n");
while(getchar() != '\n')
continue;
}
srt(library, i);
for(t = 0; t < i; t++)
{
printf("书名%s作者%s价格%.2f\n", library[t].title, library[t].author, library[t].value);
}
change(library, i);
for(t = 0; t < i; t++)
{
printf("书名%s作者%s价格%.2f\n", library[t].title, library[t].author, library[t].value);
}

return 0;

}
char * s_gets(char * st, int n)
{
char * ret_val;
char * find;

ret_val = fgets(st, n, stdin);
if(ret_val)
{
find = strchr(st, '\n');
if(find)
* find = '\0';
else
while(getchar() != '\n')
continue;
}

return ret_val;

}
void menu(void)
{
printf("*************************************************************\n");
printf(" please enter the book title and author and value \n");
printf("*************************************************************\n");
printf("输入书名\n");
}
int srt( struct book prt[], int n) //价格排序
{
int i = 0;
int j = 0;
struct book quantity;
for(i = 0; i < n-1; i++) //冒泡排序
{
int flag = 1;
for(j = 0; j < n-1-i; j++ )
{
if(prt[j].value > prt[j+1].value)
{
quantity = prt[j];
prt[j] = prt[j+1];
prt[j+1] = quantity;
flag = 0;
}
}
if(flag == 1)
break;
}
}
int change(struct book pt[], int m)
{
int i = 0;
int j = 0;
struct book letter;
for(i = 0; i < m-1; i++) //冒泡排序
{
int flag = 1;
for(j = 0; j < m-1-i; j++ )
{
if((int)pt[j].title[0]>(int)pt[j+1].title[0])
{
letter = pt[j];
pt[j] = pt[j+1];
pt[j+1] = letter;
flag = 0;
}
}
if(flag == 1)
break;
}

}

union问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
union
{
int i;
char a[2];
}*p, u;
int main(void)
{
p = &u;
p->a[0] = 0x39;
p->a[1] = 0x38;
printf("%d", sizeof(u));
printf("%d", p->i);
}