进制:
%d\%i 十进制形式输出整数
%c 输出字符
%p 输出地址
%f 输出小数
%o 八进制形式输出整数
%x 十六进制形式输出整数
内存存储:
字节 变量 内容
ffc1
ffc2 number2 0000 1101
ffc3 0000 0000
ffc4 0000 0000
ffc5 0000 0000
ffc6 number 0000 1100
ffc7 0000 0000
ffc8 0000 0000
ffc9 0000 0000
// 一个int类型数据占据4个字节、32bit
// 0000 0000 0000 0000 0000 0000 0000 1100
int number=12;// 1100
// 0000 0000 0000 0000 0000 0000 0000 1101
int number2 = 13; // 1101
先存储number,后储存number2
1.二进制转十进制
0b1100 = 0 * 2的0次方 + 0 * 2的1次方 + 1 * 2的2次方+ 1 * 2的3次方
= 0 + 0 + 4 + 8 = 12
0b1111 = 1 + 2 + 4 + 8 = 15
0b1010 = 10
2.十进制转二进制
67 = 64 + 2 + 1 = 2的6次方 + 2的1次方 + 2的0次方
= 0b1000000 + 0b10 + 0b1
= 0b1000011
3.n位二进制的取值范围
2位二进制位的取值范围:0~3 0~2的2次方-1
3位二进制位的取值范围:0~7 0~2的3次方-1
n位二进制位的取值范围:0~2的n次方-1
4个字节 -> 31bit
0 000 0000 0000 0000 0000 0000 0000 1100
0 ~ 2的31次方-1
类型说明符:
int 4个字节 %d
short 2个字节 %d
long 8个字节 %ld
long long 8个字节 %lld
signed
unsigned %u
signed和unsigned的区别:
signed 最高位要当做符号位
unsigned 最高位不要当做符号位
signed == signed int
signed 有符号:正数、0、负数
unsigned int == unsigned
unsigned 无符号:0、正数
位运算:
按位与 &
10101010000
00000100000
-------------
00000000000
10111011
10101101
---------
10101001
1001
0101
-----
0001
按位或 |
1001
0101
-----
1101
按位异或 ^
1.相同数值进行异或,结果肯定是0,比如9^9
2.交换 9^5^6 == 9^6^5
3.任何数值跟0进行异或,结果还是原来的数值,9^0 == 9
4.a^b^a == a^a^b == 0^b == b
1001
0101
-----
1100
1001
1001
-----
00000
0101
0000
----
0101
9^5^9 == 9^9^5 = 0^5 = 5
a^b^a == b
//printf("%d\n", 9^9);
//printf("%d\n", 9 ^ 5);
按位取反 ~
~0000 0000 0000 0000 0000 0000 0000 1001
1111 1111 1111 1111 1111 1111 1111 0110
//printf("%d\n", ~9);
左移 <<
0000 0000 0000 0000 0000 0000 0000 0000
00 0000 0000 0000 0000 0000 0000 100100
9<<1 -> 9 * 2的1次方 == 18
9<<2 -> 9 * 2的2次方 ==36
9<<n -> 9 * 2的n次方
//printf("%d\n", 9<<1);
右移 >>
0000 0000 0000 0000 0000 0000 0000 0000
000000 0000 0000 0000 0000 0000 0000 10
111111 1111 1111 1111 1111 1111 1111 10
8>>1 -> 8/2 == 4
8>>2 -> 8/2的2次方 == 2
8>>n -> 8/2的n次方
使用位异或运算符交换两个变量的值
借助第三方变量
int temp = a;
a = b;
b = temp;
不使用第三方变量
a = b - a;
b = b - a;
a = b + a;
使用位运算 位异或
// a^b^a == b
a = a ^ b;
b = a ^ b;
a = a ^ b;
用位与&运算符判断变量的奇偶性
15: 1111
9: 1001
14: 1110
10: 1010
a&1 == 1 // 奇数
a&1 == 0 // 偶数
if (a%2) {
printf("奇数\n");
} else {
printf("偶数\n");
}*/
//a%2==0?printf("偶数\n"):printf("奇数\n");
//a%2?printf("奇数\n"):printf("偶数\n");
写一个函数,用来输出整数在内存中的二进制形式
void printBinary(int number)
{
// 记录现在挪到第几位
// (sizeof(number)*8) - 1 == 31
int temp = ( sizeof(number)<<3 ) - 1;
while ( temp >= 0 )
{
// 先挪位,再&1,取出对应位的值
int value = (number>>temp) & 1;
printf("%d", value);
//
temp--;
// 每输出4位,就输出一个空格
if ( (temp + 1) % 4 == 0 )
{
printf(" ");
}
}
printf("\n");
}
ASCII码表
字符 ASCII码值
A 65
B 66
C 67
0 48
a 97
char:
单引号‘‘只能扩住单字节的字符
char c = ‘男‘; // 错误写法
char c = "A";// 错误写法
char c = A; // 错误写法
char c = 65;(-128 ~ 127)
1.说出下面程序的输出结构
int i = 67 + ‘4‘;
char c = ‘c‘ - 10;
printf("%d - %c\n", i, i);
printf("%d - %c\n", c, c);
2.写一个函数,将小写字母转为大写
char upper(char c)
{
// 如果是小写字母,就转成大写
/*
if (c>=‘a‘ && c<=‘z‘) { // [‘a‘, ‘z‘]
return c - (‘a‘-‘A‘);
} else {// 如果不是小写字母,返回字母本身
return c;
}*/
// 如果是小写字母,就转成大写
if (c>=‘a‘ && c<=‘z‘) { // [‘a‘, ‘z‘]
return c - (‘a‘-‘A‘);
}
// 如果不是小写字母,返回字母本身
return c;
}
数组:
使用注意
都是正确写法
int ages[5] = {10 , 11, 12, 67, 56};
int ages[5] = {10, 11};
int ages[5] = {[3] = 10, [4] = 11};
int ages[] = {10, 11, 14};
错误写法
int ages[];
错误写法
只能在定义数组的同时进行初始化
int ages[5];
ages = {10, 11, 12, 14};
正确写法
int ages[‘A‘-50] = {10, 11, 12, 14, 16};
int size = sizeof(ages);
printf("%d\n", size);
正确写法
int count = 5;
int ages[count];
ages[0] = 10;
ages[1] = 11;
ages[2] = 18;
错误写法
如果想再定义数组的同事进行初始化,数组元素个数必须是常量,或者不写
int ages[count] = {10, 11, 12};
数组的定义格式: 类型 数组名[元素个数];
数组存储:
char cs[5]= {‘a‘, ‘A‘, ‘D‘, ‘e‘, ‘f‘};
printf("%p\n", cs);
for (int i = 0; i<5; i++) {
printf("cs[%d]的地址是:%p\n", i, &cs[i]);
}
数组与函数:
数组作为函数参数,可以省略元素个数
数组作为函数参数,传递是整个数组的地址,修改函数形参数组元素的值,会影响到外面的实参数组
字符串:
char name[] = {‘i‘, ‘t‘, ‘c‘, ‘H‘, ‘s‘, ‘t‘, ‘\0‘};
char name[] = "itcast";
\0的ASCII码值是0
char name[8] = "it";
char name2[8] = {‘i‘, ‘t‘, ‘\0‘};
char name3[8] = {‘i‘, ‘t‘, 0};
char name4[8] = {‘i‘, ‘t‘};//这里隐蔽性隐藏了it字母后面有结束符,因为char name[8]表示{‘i‘,‘t‘,0,0,0,0,0,0}
但是下面的不算是一个字符串(只能说是一个字符数组)
char name5[] = {‘i‘, ‘t‘};//因为它没有结束符
"jack" == ‘j‘ + ‘a‘ + ‘c‘ + ‘k‘ + ‘\0‘
char name[10] = "jack888\n";
// 把数组传入,仅仅是个警告
printf(name);//因为printf函数里面只允许放置字符串常量
\0的作用
1.字符串结束的标记
2.printf("%s", name2);
会从name2这个地址开始输出字符,直到遇到\0为止
strlen函数:计算字符串长度
1.计算的是字符数,并不是字数。一个汉字算作3个字符
2.计算的字符不包括\0
3.从某个地址开始数字符的个数,直到遇到\0为止
编写一个函数char_contains(char str[],char c),
如果字符串str中包含字符c则返回数值1,否则返回数值0
// 可读性 -> 性能 -> 精简(重构)
int char_contains(char str[], char c)
{
int i = -1;
/*
i 3
str[++i] ‘c‘
c ‘7‘
*/
// 1.遍历整个字符串
while ( str[++i] != c && str[i] != ‘\0‘ ) ;
//return str[i] == ‘\0‘ ? 0 : 1;
return str[i] != ‘\0‘;
}
/*
int char_contains(char str[], char c)
{
int i = -1;
// 1.遍历整个字符串
while ( str[++i] )
{
// 如果发现某个字符等于参数c,直接返回1,退出函数
if (str[i] == c)
{
return 1;
}
}
// 2.说明str里面不包含字符c
return 0;
}*/
/*
int char_contains(char str[], char c)
{
int i = 0;
// 1.遍历整个字符串
while ( str[i] != ‘\0‘ )
{
// 如果发现某个字符等于参数c,直接返回1,退出函数
if (str[i] == c)
{
return 1;
}
i++;
}
// 2.说明str里面不包含字符c
return 0;
}*/
/*
int char_contains(char str[], char c)
{
// 1.遍历整个字符串
for (int i = 0; i<strlen(str); i++)
{
// 如果发现某个字符等于参数c,直接返回1,退出函数
if ( str[i] == c )
{
return 1;
}
}
// 2.说明str里面不包含字符c
return 0;
}*/
char names[2][10]= {"jack", "rose"};
printf("%s\n", names[0]);//jack
printf("%c\n", names[0][3]);//k
char names2[2][10] =
{
{‘j‘, ‘a‘, ‘c‘, ‘k‘, ‘\0‘},
{‘r‘, ‘o‘, ‘s‘, ‘t‘, ‘\0‘}
};
//等同上述的char names[2][10]= {"jack", "rose"};
指针:
变量类型 变量名;
格式:变量类型 *变量名;
定义了一个指针变量p
指针变量只能存储地址
指针就一个作用:能够根据一个地址值,访问对应的存储空间
指针变量p前面的int:指针变量p只能指向int类型的数据
注意:
不建议的写法, int *p只能指向int类型的数据
int *p;
double d = 10.0;
p = &d;
指针变量只能存储地址
int *p;
p = 200;
指针变量未经过初始化,不要拿来间接访问其他存储空间
int *p;
printf("%d\n", *p);
定义变量时的*仅仅是一个象征,没有其他特殊含义
*p = 20;//这个时候的*的作用:访问指向变量p指向的存储空间
p = 0;//清空指针
p = NULL;//清空指针
清空指针后,不能再间接访问其他存储空间
不能交换外面实参的值,仅仅是交换了内部指针的指向
void swap(int *v1, int *v2)
{
int *temp;
temp = v1;
v1 = v2;
v2 = temp;
}
交换的只是内部v1、v2的值
void swap(int v1, int v2)
{
int temp = v1;
v1 = v2;
v2 = temp;
}
符号符:
%d int
%f float\double
%ld long
%lld long long
%c char
%s 字符串
%zd unsigned long
数组与指针:
1.数组元素的访问方式
int ages[5];
int *p;
p = ages;
1> 数组名[下标] ages[i]
2> 指针变量名[下标] p[i]
3> *(p + i)
2.指针变量+1,地址值究竟加多少,取决于指针的类型
int * 4
char * 1
double * 8
任何指针都占用8个字节的存储空间(对32位系统应该位4个字节,64系统为8个字节)
char *cp;
int *ap;
long *bp;
指针变量p指向了数组的首元素
数组名就是数组的地址,也是数组首元素的地址
//p = ages;
p ---> &ages[0]
p + 1 ---> &ages[1]
p + 2 ---> &ages[2]
p + i ---> &ages[i]
内存分配划分:
1.常量区
存放一些常量字符串
2.堆
对象
3.栈
存放局部变量
掌握:
定义字符串的2种方式
1> 利用数组
char name[] = "itcast";
* 特点:字符串里面的字符是可以修改的
* 使用场合:字符串的内容需要经常修改
2> 利用指针
char *name = "itcast";
* 特点:字符串其实是一个常量字符串,里面的字符是不能修改
* 使用场合:字符串的内容不需要修改,而且这个字符串经常使用
(不包括\0)
编写一个int string_len(char *s),返回字符串s的字符长度
int string_len(char *s)
{
// 1.定义一个新的指针变量指向首字符
char *p = s;
/*
while ( *s != ‘\0‘ )
{
s++;
}*/
while ( *s++ ) ;
return s - p - 1;
}
/*
int string_len(char *s)
{
// 记录字符的个数
int count = 0;
// 如果指针当前指向的字符不是‘\0‘
// 首先*s取出指向的字符
// 然后s++
while ( *s++ )
{
// 个数+1
count++;
// 让指针指向下一个字符
//s = s + 1;
//s++;
}
return count;
}
*/
/*
int string_len(char *s)
{
// 记录字符的个数
int count = 0;
// 如果指针当前指向的字符不是‘\0‘
while ( *s != ‘\0‘)
{
// 个数+1
count++;
// 让指针指向下一个字符
//s = s + 1;
s++;
}
return count;
}*/
编写一个函数,判断某个字符串是否为回文。
回文就是从左边开始读 和 从右边开始读 都是一样的,比如"abcba"
int isHuiwen(char *str)
{
// 1.定义一个指向变量left指向字符串的首字符
char *left = str;
// 2.定义一个指向变量right指向字符串的末字符
char *right = str + strlen(str) - 1;
while (left < right)
{
// 如果左边和右边的字符不一样
if (*left++ != *right--)
{
return 0;
}
}
return 1;
}
编写一个函数void strlink(char s[], char t[])
将字符串t连接到字符串s的尾部
用数组作形参:
void strlink(char s[], char t[])
{
int i = 0;
// 判断s[i]是否为字符串的尾部
while ( s[i] != ‘\0‘ )
{
i++;
}
int j = 0;
// 拷贝t的内容到s的后面
while ( (s[i] = t[j]) != ‘\0‘ )
{
i++;
j++;
}
}
/*
更加精简的写法,仅作为参考(会有警告信息)
void strlink2(char s[], char t[])
{
int i = -1;
// 判断s[i]是否为字符串的尾部
while (s[++i]) ;
int j = 0;
// 拷贝t的内容到s的后面
while (s[i++] = t[j++]) ;
}*/
用指针作形参:
void strlink(char *s, char *t)
{
// 判断s[i]是否为字符串的尾部
while ( *s != ‘\0‘ )
{
s++;
}
// 拷贝t的内容到s的后面
while ( (*s = *t) != ‘\0‘ )
{
s++;
t++;
}
}
/*
更加精简的写法,仅作为参考(会有警告信息)
void strlink2(char *s, char *t)
{
// 判断s[i]是否为字符串的尾部
while (*s++);
// 减回一次
s--;
// 拷贝t的内容到s的后面
while ( *s++ = *t++ ) ;
}*/
指针总结:
一、指针变量的定义
1. 格式:变量类型 *指针变量名;
2. 举例:int *p; char *p2;
3. 注意:定义变量时的*仅仅是指针变量的象征
二、利用指针变量简单修改其他变量的值
1.指向某个变量
int a;
int *p;
p = &a;
或者
int *p = &a;
2.修改所指向变量的值
*p = 10;
3.在函数内部修改外面变量的值
int a = 10;
change(&a);
void change(int *n)
{
*n = 20;
}
三、指针与数组
1.将数组当做函数参数传入时,会自动转为指针
四、指针与字符串
1.定义字符串的2种方式
1> 利用数组
char name[] = "itcast";
* 特点:字符串里面的字符是可以修改的
* 使用场合:字符串的内容需要经常修改
2> 利用指针
char *name = "itcast";
* 特点:字符串其实是一个常量字符串,里面的字符是不能修改
* 使用场合:字符串的内容不需要修改,而且这个字符串经常使用
2.定义字符串数组
1> 利用二维字符数组
char names[2][10] = {"jack", "rose"};
2> 利用指针数组
char *names[2] = {"jack", "rose"};