C 语言基础知识
- 数组
- 指针
- 字符串
- 标识符(identifier)
-
- 常见的字符串处理函数
- scanf的用法
-
- [1.下面选项中的程序段,没有编译错误的是( )。](#1.下面选项中的程序段,没有编译错误的是( )。)
- [sizeof 用法](#sizeof 用法)
- 结构体
数组
数组中的易错知识点
-
定义二位数组的时候只能省略第一个[], 而不能省略第二个。
Cint x[4][] = {{1,2,3},{1,2,3},{1,2,3},{1,2,3}}; // 错误 int x[][3] = {1,2,3,4}; // 正确, 等价于int x[][3] = {{1,2,3}, {4,0,0}};
指针
指针就是内存地址,指针变量就是存储内存地址的变量。
指针=内存地址的别名,通过它,可以直接操控内存。
声明指针
c
type *var_name;
int *ip;
double *dp;
不管类型是什么,都是代表内存地址长的16位进制数。
使用指针
- *: 通过*取指针变量的值, 解引用dereference。
- & : 通过&取变量的地址
C
int var = 20;
int *ip;
ip = &var; // 存储var的地址到ip这个指针变量中
printf("var 变量的地址:%p\n", &var);
printf("ip 变量存储的地址:%p\n", ip); // 与上面的结果相同
// 使用指针访问值
printf("ip 变量的值:\d\n", *ip); // 20
// 修改所指变量
*ip = 30;
指针与数组
-
数组会"退化"成指向首元素的指针。
-
数组与指针的等价性
c
int arr[5] = {1,2,3,4,5}
int *p = arr; // 等价于int *p = &arr[0]
// 数组与指针的等价性
// arr[i] 等价 *(arr + i)
// p[i] 等价 *(p + i)
数组与指针练习题
- 请输出以下程序的结果
c
#include <stdio.h>
int main(){
int c[6] = {10,20,30,40,50,60},*p, *s;
p=c;
s=&c[5];
printf("%d\n", s-p);
return 0;
}
以上输出的结果是:
// p指针指向c;
//s 指向c[5] = 60 的指针
// s-p = s[0] - *p[0] = 60 - 10 = 50;
以上是错误分析:
重点规则:两个同类型指针相减的结果是它们之间相差的元素个数 (指针减法只有在指向同一数组)
C
p=c; // p 指向元素C的首元素即 &c[0]
s=&c[5]; // s 指向元素的index = 5 的元素 &c[5]
printf("%d\n", s-p); // 指针相减 = 5 - 0 = 5
printf("%d\n", *s-*p); //这样才是c[5] - c[0] = 60 -10 = 50
- 请输出如下结果
C
#include <stdio.h>
int f(int *q)
{
int i = 0;
for (;i <5 ; i ++)
{
(*q)++;
}
}
int main()
{
int a[5] = {1,2,3,4,5},i;
f(a);
for (i = 0 ; i <5; i ++)
{
printf("%d,", a[i]);
}
return 0;
}
结果: 6,2,3,4,5
// 关键
c
(*q)++; // 这行代码 退化成指针,指向第一个元素等价于 *q[0] 连续加上5次 = 6.
-
定义语句
int year = 2009,*p=&year;以下哪个选项不能使得year 变成2010;A: *p+=1; B: *p++; C:(*p)++; D: ++(*p);
B, 因为++ 的优先级高于*解引用,C 等价于*(p++) ; 也就是 p = p +1;
字符串
在C语言中,字符串实际上是以\0结尾的字符数组。
"\0"的ASCII码值是0.
c
char str[] = {'H','e', 'l','l','o', '\0' };
// 以上代码等价于
char str[] = "Hello";
字符串的声明与初始化的两种方式
- :字符数组,可以修改
c
char str1[10] = "Hello"; // 自动补齐'\0'
char str2[] = "Hello"; // 编译器自动计算长度,并补'\0'
char str3[10] = {'A', 'B', '\0'}; // 手动初始化
-
字符指针(不可修改)
cchar *str4 = "Hello"; // 不能修改,例如 str4[0] = 'h'; 是不允许的. 因为"Hello" 是一个字符串字面量,存储在read-ony memory中。 str4 = "HELLO"; //这是允许的,因为str4 是一个pointer variable ,存储的是内存地址,这个操作是改变了str4的指针指向字面量"HELLO"的地址。
标识符(identifier)
-
关键字:由C语言预先定义,例如 int 、if、return、static
-
预定义标识符:由C标准库定义的标识符,例如
- 函数库 printf,scanf、strlen
- 标准型名称:size_t,FILE,time_t
- 宏常量:NULL,EOF
-
用户标识符
在C语言中标识符是程序员用来命名
-
变量名
-
函数名
-
数组
-
结构体
-
枚举
-
宏
-
标签
等程序实体的名称。只能包含字母 、数字 ,下划线 ,且开头只能是字母 ,下划线 ,不能是关键字。
常见的字符串处理函数
c
#include <stdio.h>
#include <string.h>
int main()
{
char str1[] = "Hello";
char str2[2] = {'C', '\0'};
char str3[10];
int len;
// 1. copy str1 to str3
strcpy(str3, str1);
printf("strcpy(str3,str1): %s\n", str3); // strcpy(str3,str1): Hello
// 2. concat str1 and str2
strcat(str1,str2);
printf("strcat( str1, str2): %s\n", str1 ); // strcat( str1, str2): HelloC
// 3. length
len = strlen(str1);
printf("strlen(str1) : %d\n", len ); // strlen(str1) : 6
return 0;
}
注意:
- strlen(): 不包含'\0'
- sizeof():包含'\0'
scanf的用法
键盘读取字符串,行为:
-
跳过开头的空白字符串(如换行、空格,制表符)。
-
连续读取非空白字符串,直到遇到下一个空白字符或者文件结束(EOF)。
-
自动在结尾处添加'\0',构成合法的C string.
C#include <stdio.h> int main() { char str[100]; printf("Enter a word: "); scanf("%s", str); printf("You entered: %s\n", str); return 0; }
练习
1.下面选项中的程序段,没有编译错误的是( )。
- A.
char *sp, s[10]; sp = "Hello"; - B.
char *sp, s[10]; s = "Hello"; - C.
char str1[10] = "computer", str2[10]; str2 = str1; - D.
char mark[]; mark = "PROGRAM";
B 选项:s[10] 是 char数组,在C中,数组名是一个不可修改的左值,可以初始化的时候赋值,但是不能在定义后整体赋值。
C:str1. str2 都是字符数组,C 不支持数组整体赋值。
D: mark[]声明是未指定大小的初始化数组,不支持这种操作;mark同样不支持数组的整体赋值。
sizeof 用法
sizeof 并不是一个函数,是一个编译时运算符,用于获取数据类型或变量在内存中占用的字节数(byte)。
"%zu": 打印 size_t 无符号,z
- 基本用法
c
sizeof(type); // 获取类型的大小
sizeof variable; // 获取变量的大小
printf("int:%d\n", sizeof(int)); //int:4
char c = 'A';
printf("char: %zu\n", sizeof(c)); // char: 1
char str[] = "Hello";
printf("str: %zu\n", sizeof(str)); // str: 6
- 数组和指针
c
int arr[10];
int *p = arr;
printf("%zu\n", sizeof arr); // 40(10 * sizeof(int))
printf("%zu\n", sizeof p); // 8(64位系统上指针大小)