程序设计入门——C语言学习笔记Lecture 4

Lecture 4 指针与字符串

1. 指针

  指针就是保存地址的变量变量的值是内存的地址

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

  单目运算符 *:取值,用来访问指针的值所表示的地址上的变量;可以做右值也可以做左值

  • int k = *p;
  • *p = k + 1;

1.1 sizeof

是一个运算符,给出某个类型或变量在内存中所占据的字节数,例如
sizeof(int);    sizeof(i);

1.2 运算符&

获得变量的地址,它的操作数必须是变量;&不能对没有地址的东西取地址

int i; 
printf("%p", &i);

地址的字节数是否与int相同取决于编译器(32位架构还是64位架构)

int a[10]; 
printf("%p %p %p", a, &a[0], &a); 
//将输出三个相同的地址

1.3 数组与指针

1.3.1 函数参数表里的数组

  函数参数表里的数组实际上是指针,但是可以用数组的运算符[]进行运算。
  在子函数中,sizeof(a) == sizeof(int *) ;这就是为什么函数参数表里要用另外一个变量len记录数组长度,而不能直接用sizeof(a) / sizeof(a[0])计算。
  下面四种函数原型是等价的:

  • int sum(int *ar, int n);
  • int sum(int *, int);
  • int sum(int ar[], int n);
  • int sum(int [], int);

1.3.2 数组变量是特殊的指针

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

2. 字符串

2.1 大小写转换

  字母在ASCII表中是顺序排列的,大写字母和小写字母是分开排列的,并不在一起, 'a'-'A' 可以得到两端之间的距离,于是

  • a + 'a' - 'A'可以把一个大写字母变成小写字母
  • a + 'A' - 'a'可以把一个小写字母变成大写字母

2.2 逃逸字符

  用来表达无法印出来的控制字符或特殊字符,它由一个反斜杠\开头,后面跟上另一个字符,这两个字符合起来,组成了一个字符,例如:printf("请分别输入身高的英尺和英寸,如输入\"5 7\"表示5英尺7英寸:"); 以上语句中,如果不加\,则语句中的双引号的前一个"会与开头的"配对,导致程序出错。
在这里插入图片描述

2.3 字符数组与字符串

2.3.1 字符数组

  字符数组char word[]={'H', 'e', 'l', 'l', 'o', '!'}; 这不是C语言的字符串,因为不能用字符串的方式做计算。

2.3.2 字符串

字符串 char word[]={'H', 'e', 'l', 'l', 'o', '!', '\0'}; \Leftrightarrow char word[] = "Hello!";

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

2.4 定义字符串

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

2.4.1 字符串常量

  • "Hello"叫做字符串常量,会被编译器编程一个字符数组在某处,这个数组的长度是6,结尾还有表示结束的0;
  • 两个相邻的字符串常量会被自动连接起来。
  • C语言的字符串是以字符数组的形态存在的:不能用运算符对字符串做运算;通过数组的方式可以遍历字符串。
  • 唯一特殊的地方是字符串常量(即" ")可以用来初始化字符数组;以及标准库提供了一系列字符串函数。

char *s = "Hello, world!";

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

2.4.2 使用指针还是数组定义字符串?

char *s = "Hello, world!";
char s[] = "Hello, world!";
  • 数组:这个字符串在这里,作为本地变量空间自动被回收;
  • 指针:这个字符串不知道在哪里;
    • 处理参数(函数参数)
    • 动态分配空间
  • 如果要构造一个字符串 \rightarrow 数组 (可对字符串进行修改)
    如果要处理一个字符串 \rightarrow 指针(无法对字符串进行修改)

2.4.3 char*是字符串?

  • 字符串可以表达为char*的形式;
  • char*不一定是字符串;
    • 本意是指向字符的指针,可能指向的是字符的数组(就像int*一样);
    • 只有它所指的字符数组有结尾的0,才能说它所指的是字符串。
  • 常见错误:
char *string;
scanf("%s", string);

  错以为char *是字符串类型,定义了一个字符串类型的变量string就可以直接使用了;由于没有对string初始化为0,所以不一定每次运行都出错(但不知道在什么时候就会出错)

2.4.4 空字符串

char buffer[100]= "";这是一个空的字符串,buffer[0] == '\0'
char buffer[] = "";这个数组长度只有1

3.字符串输入输出

char string[8];
scanf("%s", string);    
printf("%s", string);

  scanf读入一个单词(到空格、tab或回车为止);scanf是不安全的,因为不知道要读入的内容的长度
  安全的输入:scanf("%7s", string); 在%和s之间的数字表示最多允许读入的字符的数量,这个数字应该是数组的大小减1。

4.字符串函数简介

  使用字符串函数前首先需要#include <string.h>

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

  • strcmp
    int strcmp(const char *s1, const char *s2);
    int strncmp(const char *s1, const char *s2, size_t n); (比较前n个)
    比较两个字符串,返回值0:s1== s2 ; 1(正数):s1>s2 ; -1(负数):s1<s2

  • 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);

  • strchr
    char *strchr(const char *s, int c); 从左往右找字符
    char *strrchr(const char *s, int c); 从右往左找字符
    找到则返回一个指针,该指针指向那个位置;返回NULL(0)表示没有找到

  • strstr
    字符串中找字符串

strchr函数使用示例:

#include <stdio.h>
#include <string.h>

int main()
{
	char s[]={"ABCDEFG"};
	char *p1,*p2;
 	p1=strchr(s,'B');   //strchr()用来查找某字符在字符串中首次出现的位置     
  	p2=strchr(s,'D');   
  	printf("%p\n",p1);  // 'B'首次出现的地址 
 	printf("%p\n",p2);  // 'D'首次出现的地址 
  	printf("%s\n",p1);  // 打印字符串数组某字符出现之后的字符串,包括该字符 
  	printf("%s\n",p2);

	return 0;
}

运行结果:
000000000062FE01
000000000062FE03
BCDEFG
DEFG

strchr更多应用可参考:字符串搜索函数strchr用法简介

发布了46 篇原创文章 · 获赞 84 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43871127/article/details/104273516