程序设计入门——C语言(翁凯版)第八周

8.1 指针

8.1.1 取地址运算:&取得变量的地址

  • sizeof是一个运算符,给出某个类型或变量在内存中所占据的字节数;
  • scanf(“%d”, &i)里的&是运算符,作用是获得变量的地址,它的操作数必须是变量;
  • 地址的大小是否相同取决于编译器,在64位系统和32位系统时不同;
  • &不能对没有地址的东西取地址。

8.1.2 指针:指针变量就是记录变量地址的变量

指针

  • 就是保存地址的变量;
  • int i;
  • int* p;
  • int* p,q;
  • int *p,q;

指针变量

  • 变量的值是内存的地址;
  • 普通变量的值是实际的值;
  • 指针变量的值是具有实际值的变量的地址。

作为参数的指针

  • void f(int *p);
  • 在被调用时得到了某个变量的地址;
  • int i=0;f(&i);
  • 在函数里面可以通过这个指针访问外面的这个i;

访问那个地址上的变量*

  • *是一个单目运算符,用来访问指针的值所表示的地址上的变量;
  • 可以做右值也可以做左值;
  • int k=*p;
  • *p=k+1;

传入地址

  • 为什么int i;scanf(“%d”, i);编译没有报错?
  • 因为整数和地址一样大,scanf将整数当成了地址。

8.1.3 指针与数组:为什么数组传进函数后的sizeof不对了

传入函数的数组成了什么?

  • 函数参数表中的数组实际上是指针;
  • sizeof(a)==sizeof(int*);
  • 但是可以用数组的运算符[]来计算;

数组参数

  • 以下四种函数原型等价的;
  • int sum(int &ar,int n);
  • int sum(int *,int);
  • int sum(int ar[],int n);
  • int sum(int [],int n);

数组变量是特殊的指针

  • 数组变量本身表达地址,因此;
  • int a[10];int *p=a//无需用&取地址;
  • 但是数组的但愿表达的是变量,需要用&取地址;
  • a==&[0];
  • []运算符可以对数组做也可以对指针做;
  • p[0]<==>a[0];
  • *运算符可以对指针做也可以对数组做;
  • *a=25;
  • 数组变量是const的指针,所以不能被赋值;
  • int a[]<==>int * const a;

8.2 字符类型

8.2.1 字符类型

字符类型

  • char是一种整数同时也是一种特殊的类型:字符;
  • 用单引号表示字符的字面量,如’a’、‘1’;
  • "也是一个字符;
  • printf和scanf里用%c来输入输出字符;

代码如下

#include 

int main()
{
	char c;
	char d;
	c=1;
	d='1';
	if(c==d){
		printf("相等\n");
	}else{
		printf("不相等\n");
	}
	printf("c=%d\n", c);
	printf("d=%d\n", d);
	return 0;
		
} 

输出

不相等
c=1
d=49

字符的输入输出

  • 如何输入’1’这个字符给char c?
  • scanf(“%c”, &c);——>1
  • scanf(“%d”, &i);c=i;——>49

代码如下

#include 

int main()
{
	char c;
	scanf("%c", &c);
	printf("c=%d\n", c);
	printf("c='%c'\n", c);
	return 0;
		
}  

输出

1
c=49
c='1'

当代码改成这样

#include 

int main()
{
	int i;
	char c;
	scanf("%d", &i);
	c=i;
	printf("c=%d\n", c);
	printf("c='%c'\n", c);
	return 0;
		
}  

输出

1
c=1
c=''
49
c=49
c='1'


  • ‘1’的ASCLL编码是49,所以当c==49时,它代表’1’。
  • printf(“%d %c”,c,c);
  • 一个49各自表述。

混合输入

  • scanf(“%d %c”,&i,&c);和scanf(“%d%c”,&i,&c);有何不同?

代码如下

#include 

int main()
{
	int i;
	char c;
	scanf("%d %c", &i, &c);
	printf("i=%d, c=%d, c='%c'\n", i,c,c);
	return 0;
		
}  

输出

12 1
i=12, c=49, c='1'
12a
i=12, c=97, c='a'
12  a
i=12, c=97, c='a'

当代码是下面时

#include 

int main()
{
	int i;
	char c;
	scanf("%d%c", &i, &c);
	printf("i=%d, c=%d, c='%c'\n", i,c,c);
	return 0;
		
}  

输出

12 1
i=12, c=32, c=' '
12a
i=12, c=97, c='a'
12  a
i=12, c=32, c=' '

字符计算

  • 一个字符加一个数字得到ASCLL码表中那个数之后的字符;
  • 两个字符的减,得到它们表中的距离;

大小写转换

  • 字母在ASCLL表中是顺序排列的;
  • 大写字母和小写字母是分开排列的,并不在一起;
  • ‘a’-'A’可以得到两段的距离,于是
  • a+‘a’-'A’可以把一个大写字母变成小写字母,而a+‘A’-'a’可以把一个小写字母变成大写字母。

8.2.2 逃逸字符

  • 用来表达无法印出来的控制字符或特殊字符,它由一个反斜杠“\”开头,后面跟上另一个字符,这两个字符合起来,组成了一个字符;
    程序设计入门——C语言(翁凯版)第八周_第1张图片

不同的shell会对控制字符做出不同的反应

8.3 字符串

8.3.1字符数组

字符数组

  • char word[]={‘H’,‘e’,‘l’,‘l’,‘o’,‘!’};
  • 这不是C的字符串,因为不能用字符串的方式做计算;

字符串

  • char word[]={‘H’,‘e’,‘l’,‘l’,‘o’,‘!’,‘\0’};
  • 以0(整数0)结尾的一段字符;
  • 0或’\0’是一样的,但是和’0’不同;
  • 0标志字符串的结束,但它不是字符串的一部分;
  • 计算字符串长度时候不包含这个0;
  • 字符串以数组的形式存在,以数组或指针的形式访问,更多是以指针的形式;
  • string.h里有很多处理字符串的函数;

字符串变量

  • char *str=‘Hello’;
  • char word[]=‘Hello’;
  • char line[10]=‘Hello’;

字符串常量

  • “Hello”;
  • "Hello"会被编译器变成一个字符数组放在某处,这个数组的长度是6,结尾还有表示结束的0;
  • 两个相邻的字符串常量会被自动连接起来;

字符串

  • C语言的字符串是以字符数组的形态存在的;
  • 不能用运算符对字符数组做运算;
  • 通过数组的方式可以遍历字符串;
  • 唯一特殊的地方是字符串字面量可以用来初始化字符数组;
  • 以及标准库提供了一系列字符串函数;

8.3.2 字符串变量

#include 

int main()
{
	int i=0;
	char *s="Hello World";
	char *s2="Hello World";
	printf("i=%p\n", &i);
	printf("s=%p\n",s);
	printf("s2=%p\n",s2);
	return 0;
		
}  

输出

i=000000000062FE0C
s=0000000000404000
s2=0000000000404000

字符串常量

  • char* s=“Hello World”;
  • s是一个指针,初始化为指向一个字符串常量;
  • 由于这个常量所在的地方,实际上s是const char* s,但是由于历史的原因,编译器接受不带const的写法;
  • 但是试图对s所指的字符串做写入会导致严重的后果;
  • 如果需要修改字符串,应该用数组:char s[]=“Hello World”;
#include 

int main()
{
	int i=0;
	char *s="Hello World";
	char *s2="Hello World";
	char s3[]="Hello World";
	printf("i=%p\n", &i);
	printf("s=%p\n",s);
	printf("s2=%p\n",s2);
	s3[0]='B';
	printf("Here!s3[0]=%c\n", s3[0]);
	return 0;
		
}  

输出

i=000000000062FE0C
s=0000000000404000
s2=0000000000404000
Here!s3[0]=B

指针还是数组?

  • char *str=“Hello”;
  • char word[]=“Hello”;
  • 数组:这个字符串在这里,作为本地变量空间自动被回收;
  • 指针:这个字符串不知道在哪里;处理参数;动态分配空间;
  • 如果要构造一个字符串——>数组;
  • 如果要处理一个字符串——>指针;

char是字符串?*

  • 字符串可以表达为char*的形式;
  • char*不一定是字符串;
  • 本意是指向字符的指针,可能指向的是字符的数组(就像int*一样);
  • 只有它所指的字符数组有结尾的0,才能说它所指的是字符串;

8.4 字符串计算

8.4.1 字符串输入输出

字符串赋值?

  • char* t=“title”;
  • char* s;
  • s=t;
  • 并没有产生新的字符串,只是让指针s指向了t所指的字符串,对s的任何操作就是对t做的;

字符串输入输出

  • char string[8];
  • scanf(“%s”,string);
  • printf(“%s”,string);
  • scanf读入一个单词(到空格、tab或回车为止);
  • scanf是不安全的,因为不知道要读入的内容的长度;

安全的输入

  • char string[8];
  • scanf(“%7s”,string);
  • 在%和s之间的数字表示最多允许读入的字符的数量,这个数字应该比数组的大小小一;

常见错误

  • char *string;
  • scanf(“%s”,string);
  • 以为char*是字符串类型,定义了一个字符串类型的变量就可以使用了;
  • 由于没有对string初始化为0,所以不一定每一次运行都出错;

空字符串

  • char buffer[100]=“”;
  • 这是一个空的字符串,buffer[0]==‘0’;
  • char buffer[]=“”;
  • 这个数组的长度只有1!

8.4.2 字符串函数

在string.h中有许多处理字符串的函数
strlen

  • size_t strlen(const char *s);
  • 返回s的字符串长度(不包括结尾的0);

strcmp

  • int strcmp(const char *s1,const char *s2);
  • 比较两个字符串,返回
  • 0:s1==s2;
  • 1:s1>s2;
  • -1:s1

strcpy

  • 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 *strncpy(char *restrict dst,const char *restrict src,size_t n);
  • char *strncat(char *restrict s1,const char *restrict s2,size_t n);
  • int strncmp(const char *s1,const char *s2,size_t n);

字符串中找字符

  • char * strchr(const char *s,int c);
  • char * strrchr(const char *s,int c);
  • 返回NULL表示没有找到;

你可能感兴趣的:(c语言,开发语言)