sizeof(arr),数组名表示整个数组
&arr,数组名表示整个数组
sizeof(&arr),取出整个数组地址,地址大小就为4/8。
除此之外所有数组名 表示首元素地址。
int main() {
int a[] = {1,2,3,4};
printf("%d\n", sizeof(a)); // 16
printf("%d\n", sizeof(a+0));
printf("%d\n", sizeof(*a)); // 4 数组名表示首元素地址,*a就是数组首元素,int类型4个字节。
printf("%d\n", sizeof(a+1));
printf("%d\n", sizeof(a[1])); // 4
printf("%d\n", sizeof(&a)); // 8
printf("%d\n", sizeof(*&a)); // 16 整个数组的地址解引用为整个数组的大学,等同于sizeof(a)
printf("%d\n", sizeof(&a+1));
printf("%d\n", sizeof(&a[0]));
printf("%d\n", sizeof(&a[0]+1)); // 第二个元素的地址就是4/8
return 0;
}
一、构造类型(自定义类型)
数组类型
结构体类型struct
枚举类型enum
联合类型union
指针类型
意义:决定了指针解引用操作符能访问内存中几个字节,char* p;*p访问1一个字节。而int星p访问4个字节。
字符指针
指针数组
int* p[10] = arr; 存放多个指针(地址)的数组。
数组指针
int (*p)[10]=&arr;&arr是整个数组的地址,即指向数组的指针,即存放数组的地址。
数组传参和指针传参
函数指针
存放函数地址的指针
函数指针数组
将函数存放在指针数组中,如下:
int main() {
int input = 0;
int x = 0, y = 0;
// 定义函数指针数组
int (*pArr[])(int, int) = {0, Add, Sub, Mul, Div, XoR};
do {
menu();
printf("请选择:>");
scanf("%d", &input);
if (input >= 1 && input <= 5) {
printf("请输入两个数:>");
scanf("%d%d", &x, &y);
int ret = pArr[input](x, y);
printf("%d\n", ret);
} else if (input == 0) {
printf("退出\n");
} else {
printf("选择错误\n");
}
} while (input);
return 0;
}
指向函数指针数组的指针
指向 【函数指针数组】的指针
int(*(*ppfArr[4])(int,int) = &pfArr
回调函数
空类型
空类型指针如同垃圾桶,不可进行指针解引用和加减整数的操作。因为根本不知道操作几个字节(char1int4double8)
1.整型在内存中如何存储??
正整数在内存中,原码、反码、补码相同。
负整数在内存中,原码最高符号位为1,对符号位不变的原码取反为反码,补码为对反码+1。
在内存中,整数存放的是十六进制补码。
大小端字节序存储模式:
小端模式:数据的低位存在内存的低地址位置,数据的高位存在内存的高地址位置。
如0x11223344在内存中以44332211存储,44的低位44存在低地址44位置。0x从大到小,内存中从小到大44332211。
有符号字符和无符号字符char
有符号字char范围为-128~127,unsigned char范围是0-255。
有符号和无符号数进行加法运算时,无符号数易导致死循环。
2.浮点型在内存中如何存储??
IEEE规定,S M E,二进制十六进制科学技术法。
二、字符函数与内存函数
strlen、strcpy、strcat、strncpy、strncat、strncmp与memcpy、memmove、memcmp,多n和mem通常会设比较字节的个数。
memset
三、C通讯录实现
- contact.c文件,注意包含文件的逻辑。
#include "contact.h"
//#include <stdio.h>
// 抽取查找函数,必须事先声明
static int FindByName(struct Contact *ps, char name[MAX_NAME]) {
int i = 0;
for (i = 0; i < ps->size; ++i) {
if (0 == strcmp(ps->data[i].name, name)) {
return i; // 找到了,抓取当前i值
}
}
return -1;
}
void InitContact(struct Contact *ps) {
memset(ps->data, 0, sizeof(ps->data));
ps->size = 0;
}
void AddContact(struct Contact *ps) {
if (ps->size == MAX) {
// printf("通讯录已满,无法增加\n");
return;
} else {
printf("请输入名字:>");
scanf("%s", ps->data[ps->size].name);
printf("请输入年龄:>");
scanf("%d", &(ps->data[ps->size].age));
printf("请输入性别:>");
scanf("%s", ps->data[ps->size].sex);
printf("请输入电话:>");
scanf("%s", ps->data[ps->size].tele);
printf("请输入地址:>");
scanf("%s", ps->data[ps->size].addr);
ps->size++;
printf("!!!添加成功!!!\n");
}
}
void ShowContact(const struct Contact *ps) {
if (ps->size == 0) {
printf("通讯录为空\n");
// return;
} else {
printf("%20s\t%4s\t%5s\t%12s\t%20s\n", "名字", "年龄", "性别", "电话", "地址");
for (int i = 0; i < ps->size; ++i) {
printf("%20s\t%4d\t%5s\t%12s\t%20s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].tele,
ps->data[i].addr);
}
}
}
void DelContact(struct Contact *ps) {
printf("请输入要删除的人名-联系人:>");
char name[MAX_NAME];
int i = 0;
scanf("%s", name);
// for (i = 0; i < ps->size; ++i) {
// if (0 == strcmp(ps->data[i].name, name)) {
// break; // 找到了,抓取当前i值
// }
// }
int pos = FindByName(ps, name); // 找到返回下标,找不到-1
// if (i == ps->size) {
if (pos == -1) {
printf("要删除的人不存在\n");
} else {
int j = 0;
for (j = pos; j < ps->size - 1; j++) {
ps->data[j] = ps->data[j + 1];
}
ps->size--;
printf("删除成功\n");
}
}
void SelectContact(const struct Contact *ps) {
printf("请输入要查的人名:>");
char name[MAX_NAME];
scanf("%s", name);
int pos = FindByName(ps, name);
if (pos == -1) {
printf("要查找的人不存在\n");
} else {
printf("%20s\t%4s\t%5s\t%12s\t%20s\n", "名字", "年龄", "性别", "电话", "地址");
printf("%20s\t%4d\t%5s\t%12s\t%20s\n", ps->data[pos].name, ps->data[pos].age, ps->data[pos].sex,
ps->data[pos].tele,
ps->data[pos].addr);
}
}
void UpdateContact(struct Contact* ps){
printf("请输入要修改的人名:>");
char name[MAX_NAME];
scanf("%s", name);
int pos = FindByName(ps,name);
if(pos == -1){
printf("要修改的人不存在\n");
}else{
printf("请输入名字:>");
scanf("%s", ps->data[pos].name);
printf("请输入年龄:>");
scanf("%d", &(ps->data[pos].age));
printf("请输入性别:>");
scanf("%s", ps->data[pos].sex);
printf("请输入电话:>");
scanf("%s", ps->data[pos].tele);
printf("请输入地址:>");
scanf("%s", ps->data[pos].addr);
printf("!!!修改成功!!!\n");
}
}
- contact.h文件
#define MAX 1000
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
#include <stdio.h>
#include <string.h>
struct PeoInfo{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tele[MAX_TELE];
char addr[MAX_ADDR];
};
struct Contact{
struct PeoInfo data[MAX];
int size; // 当前已有条数
};
enum Option{
EXIT,ADD,DEL,SELECT,UPDATE,SHOW,SORT
};
void InitContact(struct Contact* ps);
void AddContact(struct Contact* ps);
void ShowContact(const struct Contact *ps);
void DelContact(struct Contact *ps); // 删除指定条目
void SelectContact(const struct Contact* ps);
//int FindByName(struct Contact* ps,char name[MAX_NAME]); //不需要在这声明,加上static不向外暴露
void UpdateContact(struct Contact* ps);
- main.c文件,启动入口
#include <stdio.h>
#include "contact.c" // main.c引入contact.c,contact.c引入contact.h。
void menu() {
printf("***************\n");
printf("**1、add****2、delete***\n");
printf("**3、select**4、update*****\n");
printf("**5、show***6、sort******\n");
printf("****0、exit*******\n");
printf("***************\n");
}
int main() {
int input = 0;
// 创建通讯录
struct Contact con;
// 初始化通讯录
InitContact(&con);
do {
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input) {
case ADD:
AddContact(&con);
break;
case DEL:
DelContact(&con);
break;
case SELECT:
SelectContact(&con);
break;
case UPDATE:
UpdateContact(&con);
break;
case SHOW:
ShowContact(&con);
break;
case SORT:
break;
case EXIT:
printf("退出通讯录\n");
break;
default:
printf("选择错误\n");
break;
}
} while (input);
return 0;
}
文件
scanf/printf是针对 标准 输入流/标准输出流的 格式化输入/输出语句
fscanf/fprintf是针对 所有 输入流/所有输出流的 格式化输入/输出语句
sscanf/sprintf