1.单位换算及内存地址
代码如下:
#include <stdio.h>
int main(void){
int a, b, c;
printf("%p, %p, %p\n", &a, &b, &c); //输出abc三个变量的地址(十六进制)
//定义一个数组
int d[3];
d[0] = 1, d[1] = 2, d[2] = 3;
printf("%d, %d, %d\n", d[0], d[1], d[2]);
printf("%p, %p, %p\n", &d[0], &d[1], &d[2]); //输出数组元素的地址,且这三个元素在计算机内是连续的
return 0;
}
执行结果如下:
2.定义数组及初始化
代码如下:
#include <stdio.h>
int main(void){
//1.定义数组
//int a[2*2]; //这样是可以的,相当于int a[4];
/*
int b = 2;
int c[2*b]; //error,因为b为整型变量
*/
const int b = 2; //这样定义b为整型常量
int c[2*b]; //这样就不会报错
//int e[3.1]; //error,因为3.1不是整型
int e[int(3.1)]; //强制类型转换,这样就不会报错
int F['A']; //大写A的ASCII码为65,这样就定义了一个有65个元素的数组
int g[true]; //true为布尔型的数据,其值为1,这样就定义了一个有1个元素的数组
//2.定义并初始化数组
//完全初始化:
//int a[4] = {1, 2, 3, 4};
//int a[] = {1, 2, 3, 4}; //这两行代码都可以对数组a进行完全初始化
int a[4] = {1}; //不完全初始化。在不完全初始化中,元素如果未被初始化,将会有一个默认值0
for(int i = 0; i < 4; ++i)
printf("%d\n", a[i]);
return 0;
}
执行结果如下:
3.数组的排序
这里讲了冒泡排序和选择排序
代码如下:
#include<stdio.h>
int main(void) {
int a[7] = {89,34,-56,1,23,100,-32};
int len = 7;
//冒泡排序
/*
for(int i=0; i<len-1; ++i) {
for(int j=1; j<len-i; ++j) {
if(a[i]>a[i+j]) {
int temp=a[i];
a[i]=a[i+j];
a[i+j]=temp;
}
}
}
*/
//选择排序
for(int j=0; j<len-1; ++j) {
int c=0;
for(int i=1; i<len-j; ++i) {
if(a[c]<a[i])
c=i;
}
int b=a[c];
a[c]=a[len-1-j];
a[len-1-j]=b;
}
for(int k=0; k<len; ++k)
printf("%d,",a[k]);
putchar('\n');
return 0;
}
执行结果如下:
注意:要通过代码理解两种算法的思路
4.指针
#include <stdio.h>
void f1(int b){
b = 10;
}
void f2(int *c){
*c = 10;
}
int main(void){
int *p; //这是定义了一个指针变量,p是int *类型的,用来存放int型变量的地址
int a = 2;
p = &a; //p指向a
*p = 3; //*p等价于a
printf("%d\n", a); //结果为3
f1(a);
printf("%d\n", a); //结果为3
f2(&a); //通过函数改变main函数当中的某一个变量,就需要对这个变量取地址
printf("%d\n", a); //结果为10
int d[3]; //数组名 d是一个int *类型的常量,其值为d[0]的地址
p=d;
p[0]=1;
p[1]=2;
p[2]=3;
//printf("%d,%d,%d\n",d[-1]=1,d[3]=1;d[4]=1); //error 数组下标越界
*p=10;
*(p+1)=20; //*(d+1)=20
*(p+2)=30; //*(p+2) ->p[2] *(p+2)和*(2+p)等价 2[p]
0[p]=100;
1[p]=200;
2[p]=300;
//d = &a; //error 因为 d是一个常量
printf("%p,%p,%p\n",p,p+1,p+2); // p + n 实际上是 p + sizeof(*p)*n
for(int i=0;i<3;++i)
printf("%5d",d[i]);
return 0;
}
执行结果如下:
5.数组的增删改查及倒置
代码如下:
#include <stdio.h>
#define LEN 10
//这个函数的功能是计算数组中有效元素的个数
int length(int *a) { //参数int a[LEN] 或者 int a[]都代表是一个int *类型的变量
int j = 0;
while(j < LEN) {
if(a[j] == 0)
break;
else
++j;
}
return j;
}
//这个函数的功能是输出数组中的有效元素
void show(int a[]) {
int len = length(a);
for(int i = 0; i < len; ++i)
printf("%d\t", a[i]);
putchar('\n');
}
//这个函数的功能是删除数组中的一个有效元素
bool del(int *a, int index) {
int len = length(a);
if(len == 0 || index > len - 1 || index < 0)
return false;
else {
for(int i = index + 1; i < len; ++i)
a[i-1] = a[i];
a[len -1] = 0;
return true;
}
}
//这个函数的功能是插入一个元素
bool insert(int *a, int index, int value) {
int len = length(a);
if(len == LEN || index < 0 || index > len)
return false;
else {
for(int i = len - 1; i >= index; --i)
a[i+1] = a[i];
a[index] = value;
return true;
}
}
//这个函数的功能是倒置数组
void invert(int* a) {
int len = length(a);
int from = 0;
int end = len - 1;
while(from < end) {
int d = a[from];
a[from] = a[end];
a[end] = d;
from++;
end--;
}
}
//这个函数的功能是通过值来查找位置
int find1(int *a, int value) {
int len = length(a);
for(int i = 0; i < len; ++i) {
if(a[i] == value)
return i;
}
return -1;
}
//二分查找(折半查找)
/* 二分查找的条件
用于查找的内容逻辑上来说是需要有序的
查找的数量只能是一个,而不是多个
*/
int find2(int *a, int value) {
int len = length(a);
int from = 0;
int end = len - 1;
while(from <= end){
if(value == a[(from + end)/2])
return (from + end)/2;
else if(value > a[(from + end)/2])
from = (from + end)/2 + 1;
else
end = (from + end)/2 - 1;
}
return -1;
}
int main(void) {
int a[LEN] = {3,6,9,12,15};
/*
if(del(a,5))
show(a);
else
printf("删除失败!\n");
printf("有效元素的个数为:%d\n", length(a));
*/
// insert(a, 2, 8);
// invert(a);
printf("%d\n", find2(a, 15));
show(a);
return 0;
}
执行结果如下:
6.二维数组定义时的初始化
代码如下:
#include <stdio.h>
int main(void) {
//完全初始化
//int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; //完全初始化1
/* 完全初始化2
int a[3][4] = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
*/
//不完全初始化
//int a[3][4] = {1}; //不完全初始化1
//int a[3][4] = {{1,2,3,4},{},{9,10,11,12}}; //不完全初始化2
//int a[3][4] = {{1},{2,3},{4}}; //不完全初始化3
//int a[3][4] = {{1},{2,3}}; //不完全初始化4
int a[][4] = {1,2,3,4,5,6,7,8,9,10,11}; //不完全初始化5
/* 输出方式1
for(int i = 0; i < 3; ++i) //表示行标
for(int j = 0; j < 4; ++j) //表示列标
printf("%d\n", a[i][j]);
*/
//输出方式2
for(int i = 0; i < 12; ++i)
printf("%d\n", a[i/4][i%4]);
return 0;
}
执行结果如下:
7.通过指针引用多维数组
答案:
&a[1] 1012
a[1]+2 1020
*(a+0)+1 1004
&a[1][1] 1016
*(*(a+1)+2) 6
8.求二维数组的鞍点
代码如下:
#include <stdio.h>
#define M 5
#define N 6
//出具有m行n列二维数组的"鞍点",即该位置上的元素在该行上最大,在该列上最小
void show(int a[M][N]){ //int a[][N] 或者 int(*a)[N]都是定义了一个指向含有N个整型元素的数组的指针
for(int i = 0; i < M; ++i){
for(int j = 0; j < N; ++j){
printf("%-5d",a[i][j]);
}
putchar('\n');
}
}
bool f(int (*a)[N], int i , int j){ //判断a[i][j]是不是j列上最小的元素
for(int x = 0; x < M; ++x){
if(a[x][j] < a[i][j])
return false;
}
return true;
}
int main(void){
int a[M][N];
for(int i = 0; i < M*N; ++i)
a[i/N][i%N] = i;
show(a);
for(int i = 0; i < M; ++i){
int k = 0;
for (int j = 1; j < N; ++j){
if(a[i][k] < a[i][j])
k = j;
}
if(f(a, i, k))
printf("a[%d][%d]是这个二维数组的鞍点\n", i, k);
}
return 0;
}
执行结果如下:
9.字符数组
代码如下:
#include <stdio.h>
int main(void){
char a[10] = {'h', 'a', ' ', 'h', 'a', '\n'}; //'\0'空字符 是C语言中字符串结束的标志
//上面是不完全初始化,未被初始化的字符就自动赋为'\0'
printf("haha\0hehe"); //输出haha
printf("%s", "ABCD"); //字符串常量末尾都有一个空字符
printf("%s",a);
//字符型数组定义时初始化所特有的形式
char b[10] = {"ha ha\n"};
char c[10] = "ha ha\n";
char d[] = "ha"; //d数组中共有几个元素? 答案:3个,因为还有一个\0
//c = "ha ha\n"; //error 因为c是一个char *类型的常量
char * ch = "ha ha \n"; //字符串常量在计算机的内存当中是一个没有名字的数组
printf("AAA%s", ch);
return 0;
}
执行结果如下:
10.字符串的输入和输出
代码如下:
#include <stdio.h>
void show(char *a, int len){
for(int i = 0; i < len; ++i){
printf("%d\n", a[i]);
}
}
int main(void){
char a[30], b[30], c[30], ch;
//使用scanf输入多个字符串时,用空格,tab或者换行来分隔
/*
scanf("%s%s%s%c", a, b, c, &ch); //如果输入项是字符数组的数组名,或者是char *类型的变量,就不需要加取地址符
printf("%s%s%s%c\n", a, b, c, &ch);
show(a,30); //a数组当中没有被赋值的元素 是一个垃圾值
*/
/* gets函数:
功能:将用户输入的一行文字放到数组a的元素当中
和scanf函数一样,都会把字符数组当中的一个元素赋值为空字符。
不同点:1.gets可以把空格、tab赋给这个字符数组的元素
2.gets会丢弃换行符
*/
/* puts函数:
puts()函数用来向标准输出设备屏幕输出字符串并换行
具体是把字符串输出到屏幕上,将‘\0’转换为回车换行。调用方式是:puts(str)。其中str是字符串数组名或者字符串指针。实际上,数组名就是指针。
*/
/*
gets(a);
ch = getchar();
puts(a);
putchar(ch);
*/
puts("haha"); //puts输出该字符串之后 再输出一个换行符
int x=2,y=3;
printf("x=%d,y=%d\n",x,y);
//char *p = "x=%d,y=%d\n";
char *p = "x=%#x,y=%#x\n";
printf(p,x,y); //printf和scanf被称为可变格式输出输入函数
return 0;
}
执行结果如下:
11.处理字符串的函数
代码如下:
#include <stdio.h>
//这个函数的功能是计算字符串的长度
int strlen(char* a){
if(a == NULL)
return 0;
int len = 0;
while(a[len] != 0)
len++;
return len;
}
//这个函数的功能是将字符串中大写字母转成小写字母
char * strlwr(char* a){
if(a == NULL)
return NULL;
char * a1 = a;
while(*a != '\0'){
if(*a <= 'Z' && *a >= 'A')
*a += 32;
++a;
}
return a1;
}
//这个函数的功能是将字符串中小写字母转成大写字母
char * strupr(char* a){
if(a == NULL)
return NULL;
char * a1 = a;
while(*a != '\0'){
if(*a <= 'z' && *a >= 'a')
*a -= 32;
++a;
}
return a1;
}
//这个函数的功能是复制字符串
char * strcpy(char * a, char * b){
if(a == NULL || b == NULL)
return a;
char * a1 = a;
while((*a = *b) != '\0'){
a++;
b++;
}
return a1;
}
//这个函数的功能是拼接字符串
char * strcat(char * a, char * b){
if(a == NULL || b == NULL)
return a;
char * a1 = a;
while(*(a++) != '\0')
;
a--;
while((*a = *b) != '\0'){
a++;
b++;
}
return a1;
}
//这个函数的功能是将b字符串的前n个元素覆盖a字符串的前n个元素
char * strncpy(char * a, char * b, int n){
if(a == NULL || b == NULL)
return a;
char * a1 = a;
for(int i = 0; i < n; ++i){
a[i] = b[i];
}
return a1;
}
//这个函数的功能是比较两个字符串的大小
int strcmp(char * a, char * b){
if(a == NULL || b == NULL)
return 2;
do{
if(*a == '\0' && *b =='\0')
return 0;
else if(*a < *b)
return -1;
else if(*a > *b)
return 1;
a++, b++
}while(true);
}
int main(void){
char a[] = "ABChaha";
printf("%d\n", strlen(a)); //输出7
printf("%s\n", strlwr(a)); //输出abchaha
printf("%s\n", strupr(a)); //输出ABCHAHA
printf("%s\n", strcpy(a, "lala")); //输出lala
//printf("%s\n", strcpy(a, "lala123456777777777")); //error 因为字符串a长度仅为7
printf("%s\n", strcat(a,"123")); //输出lala123
printf("%s\n", strncpy(a, "abcdef", 4)); //输出abcd123
printt("%d\n", strcmp("abcde", "abde")); //输出-1
return 0;
}
执行结果如下:
实际上,这些函数在string.h中都是包含的
12.习题1
题目要求:输出以下杨辉三角形(要求输出10行)
代码如下:
#include <stdio.h>
#define N 10
void show(int a[N][N]){
for(int i = 0; i < N; ++i){
for(int j = 0; j <= i; ++j)
printf("%6d", a[i][j]);
putchar('\n');
}
}
int main(void){
int a[N][N]={0};
for(int i = 0; i < N; ++i){
a[i][0] = 1;
}
for(int i = 1; i < N; ++i){
for(int j = 1; j <= i; ++j)
a[i][j] = a[i-1][j-1] + a[i-1][j];
}
show(a);
return 0;
}
运行结果如下:
13.习题2
题目要求:有n个整数,使前面各数顺序向后移m个位置,最后m个数变成最前面m个数,如下图
代码如下:
#include <stdio.h>
#define N 10
void show(int a[]){
for(int i = 0; i < N; ++i)
printf("%6d", a[i]);
putchar('\n');
}
void move(int *a, int k, int index){
for(int i = 0; i < k; ++i){
int d = a[index];
a[index] = a[index - 1];
a[index - 1] = d;
index--;
}
}
int main(void){
int a[N];
for(int i = 0; i < N; ++i)
a[i] = i;
show(a);
int m;
do{
printf("请输入m的值:");
scanf("%d", &m);
if(m >= 0 && m <=N)
break;
printf("输出有误!\n");
}while(1);
for(int i = N-m; i < N; ++i){
move(a, N-m, i);
}
show(a);
return 0;
}
执行结果如下:
14.习题3
题目要求:有n个人围成一圈,顺序排号。从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下来的原来是第几号的那位。
代码如下:
#include <stdio.h>
int main(void){
int a[1000] = {0};
printf("请输入总人数:");
int n;
scanf("%d", &n);
for(int i = 0, cnt = 0, sum = 0; sum != n-1; ++i){
if(a[i%n] == 3)
continue;
if(a[i%n] = (cnt++)%3+1 == 3)
sum++;
}
int i;
for(i = 0; i < n; ++i)
if(a[i] != 3)
break;
printf("最后留下的是原来的第%d个人\n", i+1);
return 0;
}
执行结果如下: