一、指针
sizeof
是一个运算符,给出某个类型或变量在内存中所占的字节数。
%ld 表示输入输出为长整型
运算符&
scanf("%d",&i); 里的&
获得变量的地址,它的操作数必须是变量
int i; printf("%x",&i);
地址的大小是否与int类型相同取决于编译器
inti; printf("%p",&i);
地址的大小是否与int类型相同取决于
%x 以16进制输出变量地址
%p 打印地址
%lu 输出无符号长整型整数 (long unsigned)
&不能取的地址
&不能对没有地址的东西取地址
&(a+b) &(a++) &(++a)
可取的地址
变量的地址
相邻的变量的地址,,,差距永远是4
&的结果的sizeof
数组的地址,,,第0位的地址
数组单元的地址,,,第0位的地址
相邻的数组单元的地址,,,差距是4
堆栈stack是自上而下的
指针
就是保存地址的变量
int i;
int* p = &i;
int* p,q;
int *p,q;
int* p,q; == int *p,q;(意思是一样的)
*p是一个int
指针变量
变量的值是内存的地址
普通变量的值是实际的值
指针变量的值是具有实际值的变量的地址
作为参数的指针
void f(int *p);
在被调用的时候得到了某个变量的地址;
int i=0; f(&i);
在函数里面可以通过这个指针访问外面的i
访问那个地址上的变量 *
*是一个单目运算符,用来访问指针的值所在的地址上的变量
可以做右值也可以做左值
int k = *p;
*p = k+1;
数组参数
以下四种函数原型是等价的:
int sum(int *ar, int n);
int sum(int *, int);
int sum(int ar[], int n);
数组变量是特殊的指针
数组变量本身表达地址,所以
int a[10]; int *p=a; //无需用&取地址
但是数组的单元表达的是变量,需要用&取地址
a == &a[0]
[]运算符可以对数组做,也可以对指针做:
p[0] <==> a[0]
*运算符可以对指针做,也可以对数组做:
*a = 25;
数组变量是const的指针,所以不能被赋值
int a[] <==> int * const a=...
二、字符类型
char是一种整数,也是一种特殊的类型:字符。这是因为: (character)
用单引号表示的字符字面量:‘a’, ‘1’
"也是一个字符
printf和scanf里用%c来输入输出字符
字符的输入输出
如何输入‘1’这个字符给char c
scanf("%c",&c); ——>1
scanf("%d",&i); c=i; ——>49
'1'的ASCII编码是49,所以当c==49时,它代表'1'
一个49各自表述!
%c:以字符形式输出,
混合输入
注意输入的空格
scanf("%d %c",&i ,&c);
scanf("%d%c",&i ,&c);
字符计算
一个字符加一个数字得到ASCII码表中那个数之后的字符
两个字符的减,得到它们在表中的距离
大小写转换
’a‘-’A‘可以得到两段之间的距离,于是
a+’a‘-’A‘可以把大写变小写;
a+‘A‘-’a‘可以把小写变大写;
要变的-原先的
大变小
#include<stdio.h>
int main()
{
char c = 'A';
int i=c+'a'-'A';
printf("%c\n",i);
return 0;
}
小变大
#include<stdio.h>
int main()
{
char c = 'a';
int i=c+'A'-'a';
printf("%c\n",i);
return 0;
}
逃逸字符
用来表达无法印出来的控制字符或特殊字符,它由一个反斜杠“\”开头,后面跟上另一个字符,这两个字符合起来,组成了一个字符
printf("请分别输入身高的英尺和英寸,"
“如输入\"5 7\"表示5英尺7英寸:”);
三、字符串
以0(整数0)结尾的一串字符
以0或'\0'是一样的,但是和'0'不同
0标志字符串的结束,但它不是字符串的一部分
计算字符串长度的时候不包含这个0
字符串以数组的形式存在,以数组或指针的形式存在
更多的是以指针的形式
string.h里有很多处理字符串的
char *str = "Hello"; 有一个名为str的指针,它指向了这个字符数组这里面放的内容是Hello
char word[] = "Hello"; 有一个字符数组,里面的内容是Hello
char line[10] = "Hello"; 有一个字符数组line,line数组里面有10个,数组里面有是个字节那么大,往里面放了Hello,这个Hello里面有5个字符,加上‘0’总共六个。
字符串常量
"Hello" 字符串常量,
"Hello" 会被编译器变成一个字符数组放在某处,这个数组的长度是6,结尾还有表示结束的0
两个相邻的字符串常量会被自动连接起来
唯一特殊的地方是字符串字面量可以用来初始化字符数组
以及标准库提供了一系列字符串函数
字符串
C语言的字符串是以字符数组的形态存在的
不能用运算符对字符串做运算
通过数组的方式可以遍历字符串
字符串变量的两种形式
char* s = "Hello,world!";
char word[]= "Hello,world!";
作为数组:字符串在这里
作为本地变量空间自动被回收
作为指针:字符串不知道在哪里
处理参数
动态分配空间
如果要构造一个字符串——>数组
如果有处理一个字符串——>指针
s是一个指针,初始化为指向一个字符串常量
由于这个常量所在的地方,所以实际上s是const char *s,但是由于历史的原因,编译器接受不带const的写法
但是试图对s所指的字符串做写入会导致严重的后果
#include<stdio.h>
int main(void)
{
int i = 0;
char *s = "Hello World";
char *s2 = "Hello World";
//s[0] = 'B';
printf("s =%p\n",s);
printf("s2=%p\n",s2);
printf("&i=%p\n",&i);
//printf("Here!s[0]=%c\n",s[0]);
return 0;
}
输出为
s =0000000000404000
s2=0000000000404000
&i=000000000061FE0C
s和s2地址很小,因为s和s2存在于只读代码段。而且是只读的。
如果需要修改字符串,应该用数组的方式定义:
char s[] = "Hello,world!";
char*是字符串?
字符串可以表达为char*的形式
char*不一定是字符串
本意是指向字符的指针,可能指向的是字符的数组(就像int*一样)
只有它所指的字符数组有结尾的0,才能说它所指的是字符串
四、字符串计算
字符串赋值
char *t = "title";
char *s;
s = t;
并没有产生新的字符串,只是让指针s指向了t所指的字符串,对s的任何操作就是对t做的.
字符串输入输出
(string: 字符串)
char string[8];
scanf("%s",string);
printf("%s",string);
scanf读入一个单词(到空格、tab或回车为止)
scanf是不安全的,因为不知道要读入的内容的长度
安全的输入
char string[8];
scanf("%7s",string);
在%和s之间的数字表示最多允许读入的字符的数量,这个数字应该比数组的大小小一
下一次scanf从上一个读完的结尾开始。
常见错误
char *string;
scanf("%s",string);
以为char*是字符串类型,定义了一个字符串类型的变量string就可以直接使用了。
由于没有对string初始化为0,所以不一定每次运行都出错。
指针要初始化!!
空字符串
相邻的紧挨着的两个双引号是一个空的字符串(也是有效的字符串)
char buffer[100]="";
这是一个空的字符串,buffer[0] == '\0'
char buffer[] = '';
这个数组的长度只有1
字符串函数
string.h
#include<string.h>
strlen(lenth长度)
size_t strlen(const char *s);
返回s的字符串长度(不包括结尾的0)
strcmp (compare比较)
int strcmp(const char *s1, const char *s2);
比较两个字符串,返回:
0:s1 == s2
1: s1 > s2
-1: s1 < s2
strcpy(copy)
char *strcpy(char *restrict dst, const char *restrict src);
把src的字符串拷贝到dst
restrict表明src和dst不重叠(C99)
返回dst
为了能链起代码来
strcat(链接)
char *strcat(char *restrict s1, const char *restrict s2);
把s2拷贝到s1的后面,接成一个长的字符串
返回s1
s1必须具备足够的空间
strcpy和strcat都可能出现安全问题
如果要拷贝\链接的地方没有足够的空间,就会出现问题
安全版本
char *strcpy(char *restrict dst, const char *restrict src, size_t n);
char *strcat(char *restrict s1, const char *restrict s2, size_t n);
int strncmp(const char *s1, const char *2, size_t n);
n:比较前n个数
n:最多只能操作的字符数
strchr(字符串中找字符)
char *strchr(const char *s, int c); //在字符串s中,寻找c第一次出现的位置。从左边数(返回的是指针)
char *strrchr(const char *s, int c); //从右边找
返回NULL表示没有找到
strstr