当前位置: 代码迷 >> 综合 >> 【Day4 C语言基础语法学习-3】
  详细解决方案

【Day4 C语言基础语法学习-3】

热度:80   发布时间:2023-11-30 18:19:57.0

Day4 C语言基础语法学习-3

  • 一 数组
    • 1.1 数组的概念
    • 1.2 一维数组
      • 1.2.1 一维数组的定义
    • 1.2.2 一维数组的性质
    • 1.3 一维数组的初始化和遍历
    • 1.4 冒泡排序法
  • 二、二维数组
  • 2.1 二维数组的定义和性质
  • 2.2 二维数组的初始化和遍历
  • 三、字符数组和字符串
    • 3.1 字符串逆序
    • 3.2 插入数据
  • 四 字符串函数
    • 4.1 为什么要使用字符串函数
    • 4.2 常用字符串函数
      • 4.2.1 strlen()
      • 4.2.2 strcmp()
      • 4.2.3 strcpy()
      • 4.2.4 strcat()
      • 4.2.5 自己实现strcpy函数的功能
  • 五、指针概念
    • 5.1 指针的用途
    • 5.2 指针的概念
    • 5.2指针变量的运算
      • 5.2.1 算术运算符
      • 5.2.2 关系运算符
      • 5.2.3 赋值运算
      • 5.2.4 练习:输入一个字符串,将字符串的元素翻转
  • 六、指针和一维数组
    • 练习1:通过指针自己实现strlen函数的功能
    • 练习2: 通过指针实现strcpy函数的功能
  • 作业:
    • 1.通过指针实现strcat功能
    • 2.实现atoi函数的功能
    • 3. 输入一个字符串,输出字符串中有多少个空格
    • 4. 输入两个字符串,判断一个字符串是否为另一个的子串

一 数组

1.1 数组的概念

数组:
保存一组相同类型的数据
不管是几维数组,都是开辟一段连续的内存空间
数组是一种构造数据类型(数组,结构体,共用体)

1.2 一维数组

1.2.1 一维数组的定义

<存储类型> <数据类型> <数组名> [数组下标]

存储类型:auto,register,static,extern
数据类型:基本数据类型:int,char,float…等
数组名:是一个标识符,满足标识符的命名规则
数组下标:确定数组张元素的个数

例如:

int a[10];

含义:定义一个名为a的数组,一共10个元素,每个元素都是int类型。

1.2.2 一维数组的性质

#include <stdio.h>int main(int argc, const char *argv[])
{int a[4];a[0] = 222;a[1] = 333;a[2] = 444;a[3] = 555;printf("%d %d %d\n",a[0],a[1],a[2]);//数组在定义和使用的时候,数组下表尽量不要使用变量//防止后期变量改变会影响对数组的操作,一般数组下标都是常量或者常量表单大师,宏定义本身也是一个常量表达式,所以可以当做数组下标使用#if 0int num = 10;int b[num];b[2] = 5;int n =3;b[n] = 888;printf("%d %d\n",b[2],b[n]);#endifprintf("sizeof(a) = %ld %ld\n",sizeof(a),sizeof(int)*4);printf("%p\n",&a[0]);printf("%p\n",&a[0]+1);printf("%p\n",a);printf("%p\n",a+1);printf("%p\n",&a);printf("%p\n",&a+1);a++;  //数组名是常指针,不能修改return 0;
}

1.3 一维数组的初始化和遍历

1.全部初始化
2.局部初始化
3.全部初始化不指定数组下标

#include <stdio.h>int main(int argc, const char *argv[])
{//如果在函数内部定义一个数组没有初始`在这里插入代码片`化,那么每一个元素都是随机值//int a[5];//a = {1,2,3,4,5};  //错误写法//全部初始化//int a[5] = {1,2,3,4,5};//int a[5] = {0};  //全部初始化为0//int a[5] = {};  //有的编译器不支持此种写法//int a[5] = {1,2,3};  //局部初始化,没有赋值的元素自动初始化为0int a[] = {1,2,3,4,5,6,7};  //不指定数组下标,系统会根据初始化的数据的个数设置数组下标printf("sizeof(a) = %ld\n",sizeof(a));/*一维数组的遍历*/int i;for(i = 0 ; i < sizeof(a)/sizeof(a[0]);i++){printf("%d ",a[i]);//printf("a[%d] = %d\n",i,a[i]);}putchar(10);return 0;
}

1.4 冒泡排序法

在这里插入图片描述

#include <stdio.h>int main(int argc, const char *argv[])
{int a[10] = {0};printf("请输入10个数字:\n");int i,j;int length = sizeof(a)/sizeof(a[0]);for(i = 0 ; i < length;i++){scanf("%d",&a[i]);}for(i = 0 ; i < length - 1;i++){for(j = 0 ; j < length - 1 - i;j++){if(a[j] < a[j+1]){#if 0//数据交换,方式1int t = a[j];a[j] = a[j+1];a[j+1] = t;#endif//数据交换,方式2	a[j] = a[j] + a[j + 1];a[j + 1] = a[j] - a[j + 1];a[j] = a[j] - a[j + 1];}}}for(i = 0 ; i < length;i++){printf("%d ",a[i]);}putchar(10);return 0;
}

二、二维数组

2.1 二维数组的定义和性质

书写方式:
存储类型 数据类型 数组名 [行数][列数];
例如:

int arr[3][4];

#include <stdio.h>int main(int argc, const char *argv[])
{int a[2][3] = {
   {1,2,3},{4,5,6}};//int a[2][3] = {
   {1},{4,5}};//int a[][3] = {
   {1,2,3},{4,5,6}};//int a[][3] = {1,2,3,4,5,6,7,8};//int a[2][3] = {0};int i,j;for(i = 0;i < 3;i++){for(j =0 ; j < 3;j++){printf("a[%d][%d] = %d\n",i,j,a[i][j]);}}printf("%p\n",&a[0][0]);printf("%p\n",&a[0]);printf("%p\n",a);printf("%p\n",&a);printf("%p\n",&a[0][0] + 1);printf("%p\n",&a[0] + 1);printf("%p\n",a + 1);printf("%p\n",&a + 1);return 0;
}

2.2 二维数组的初始化和遍历

#include <stdio.h>int main(int argc, const char *argv[])
{//int a[3][4];//int a[2][3] = {
   {4,5,6},{7,8,9}};//全部初始化//int a[2][3] = {1,2,3,4};   //按行存储,没有设置的自动补0//int a[2][3] = {
   {1},{2}};//int a[][3] = {
   {10,20},{30}};//int a[2][] = {1,2,3,4,5};  //错误写法int i,j;//外层循环控制行数//内层循环控制列数for(i = 0 ; i < 2;i++){for(j = 0 ; j < 3;j++){printf("%-5d",a[i][j]);}putchar(10);}return 0;
}

三、字符数组和字符串

字符数组:数组里面保存的每一个元素都是字符
字符串本质也是一个字符数组

#include <stdio.h>int main(int argc, const char *argv[])
{char ch1[] = {'h','e','l','l','o'};printf("sizeof(ch1) = %ld\n",sizeof(ch1));//字符数组的遍历int i;for(i = 0; i < sizeof(ch1)/sizeof(ch1[0]);i++){printf("%c ",ch1[i]);}putchar(10);char ch2[] = "world";printf("sizeof(ch2) = %ld\n",sizeof(ch2));printf("ch2 = %s\n",ch2);char ch3[] = {'h','e','l','l','o','\0'};printf("ch3 = %s\n",ch3);char ch4[] = "hello\0world";printf("sizeof(ch4) = %ld\n",sizeof(ch4));for(i = 0 ; i < sizeof(ch4)/sizeof(ch4[0]);i++){printf("[%c] %d\n",ch4[i],ch4[i]);}puts("---------------------------------------");char str[4][32] = {"hello","nihao beijing","hello kitty","welcome to nanjing"};int j;for(i = 0 ; i < 4;i++){for(j = 0 ; j < 32;j++){printf("%c",str[i][j]);}putchar(10);}return 0;
}

3.1 字符串逆序

#include <stdio.h>int main(int argc, const char *argv[])
{char str[32] = {0};printf("请输入一个字符串: ");scanf("%s",str);int i = 0,length = 0;while(str[i] != '\0'){length++;i++;}int x = 0, y = length -1;for(i = 0 ; i < length /2 ;i++){char t = str[x];str[x] = str[y];str[y] = t;x++;y--;}printf("%s\n",str);return 0;
}

3.2 插入数据

输入一个字符串,位置,插入的元素
在这里插入图片描述

#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{char str[32] = {0};int num,i;char ch;printf("请输入字符串,位置,插入的元素:\n");scanf("%s%d %c",str,&num,&ch);int length = strlen(str);for(i =0 ; i < length - num +1;i++){str[length - i] = str[length -i - 1];}str[num - 1] = ch;printf("%s\n",str);return 0;
}

四 字符串函数

4.1 为什么要使用字符串函数

一般字符串都是保存在一个数组里面,但是数组定义好之后,是不能整体操作的,所以我们需要借助一下字符串相关操作的函数来对字符串进行操作

#include <stdio.h>
int main(int argc, const char *argv[])
{char s1[] = "hello world";char s2[] = "hello world";if(s1 == s2){printf("s1 = s2\n");}else{printf("s1 != s2\n");}//数组如果没有初始化,数组下标必须写//char str[];return 0;
}

4.2 常用字符串函数

4.2.1 strlen()

头文件:#include <string.h>
原型:size_t strlen(const char *s);
功能:获取一个字符串的长度
参数:s:要获取长度的字符串
直接传入一个字符串,或者字符数组名都可以
返回值:字符串的长度

#include <stdio.h>
#include <string.h>int main(int argc, const char *argv[])
{//strlen函数获取字符串的长度//获取的长度是这个字符串中第一\0位置之前的长度,不包括\0char s1[] = "hello world";printf("strlen(s1) =%ld\n",strlen(s1));printf("sizeof(s1) =%ld\n",sizeof(s1));char s2[] = "hello wor\0ld";printf("strlen(s2) =%ld\n",strlen(s2));printf("sizeof(s2) =%ld\n",sizeof(s2));//以下这个不是一个字符串,没有\0,所以不能用strlen来获取字符串长度,strlen会一直从首地址的位置找\0char s3[] = {'h','e','l','l','o'};printf("strlen(s3) =%ld\n",strlen(s3));printf("sizeof(s3) =%ld\n",sizeof(s3));char s4[32] = "hello world";printf("strlen(s4) =%ld\n",strlen(s4));printf("sizeof(s4) =%ld\n",sizeof(s4));return 0;
}

4.2.2 strcmp()

头文件:#include <string.h>
原型:int strcmp(const char *s1, const char *s2);
功能: 比较两个字符串的大小
参数:s1,s2两个字符串
返回值:
0: s1 = s2
<0: s1 < s2
>0: s1 > s2
int strncmp(const char *s1, const char *s2, size_t n);
用于比较两个字符串前n个字节是否一样

#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{//strcmp比较的是\0之前的内容,跟字符串所在内存空间没有关系//char s1[32] = "hello w\0orld";//char s2[] = "hello w\0orld";char s1[] = "h";char s2[] = "hello abcdefgwhi";int ret = strcmp(s1,s2);if(ret == 0){printf("s1 = s2\n");}else if(ret > 0){printf("s1 > s2\n");}else{printf("s1 < s2\n");}int k = strncmp(s1,s2,2);if(k == 0){printf("s1 = s2\n");}else if(k > 0){printf("s1 > s2\n");}else{printf("s1 < s2\n");}return 0;
}

4.2.3 strcpy()

头文件:#include <string.h>
原型:char *strcpy(char *dest, const char *src);
功能: 将src字符串赋值到dest字符串中
参数:
dest:目的字符串
src:源字符串
返回值:
返回目的字符串的首地址

char *strncpy(char *dest, const char *src, size_t n);

#include <stdio.h>#include <string.h>
int main(int argc, const char *argv[])
{char s1[32];strcpy(s1,"hello world");printf("s1 = %s\n",s1);char s2[] = "hello world";char s3[32] = "abcdefg";//strcpy将 s3中的第一个\0复制给了s2strcpy(s2,s3);printf("sizeof(s2) = %ld\n",sizeof(s2));printf("s2 = %s\n",s2);int i;for(i = 0 ; i < sizeof(s2)/sizeof(s2[0]);i++){printf("[%c] %d\n",s2[i],s2[i]);}puts("------------------------");char buf1[32] = "hello world";char buf2[32] = "abcdefghijklmnopqrsst";//strcpy(buf1,buf2);//是将第二个参数的前n个字节复制给第一个参数strncpy(buf1,buf2,7);printf("buf1 = %s\n",buf1);return 0;
}

4.2.4 strcat()

头文件:#include <string.h>
原型:char *strcat(char *dest, const char *src);
功能: 将src追加到dest的后面
参数:
dest:目的字符串
src:源字符串
返回值:
追加后字符串的首地址

char *strncat(char *dest, const char *src, size_t n);

#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{char s1[32] ="hello wo\0rldadadjajdalsdkjaskdj";  //hello woabcdefg\0char s2[32] ="abcdefg\0higk";strcat(s1,s2);printf("s1 = %s\n",s1);return 0;
}

4.2.5 自己实现strcpy函数的功能

#include <stdio.h>
int main(int argc, const char *argv[])
{char s1[32] = "welcome to nanjing";char s2[32] = "hello world";int i = 0;while(s2[i] != '\0'){s1[i] = s2[i];i++;}s1[i] = s2[i];printf("s1 = %s\n",s1);return 0;
}

五、指针概念

5.1 指针的用途

使用程序简洁,紧凑,高效
有效地表示复杂的数据结构
动态分配内存
得到多于一个函数的返回值

5.2 指针的概念

当程序中定义一个变量之后,程序就会为这个变量在内存中开辟内存空间,我们内存中每一个字节的空间都有一个编号,将这个编号称之为地址,地址也叫做指针

在不影响理解的情况,有时对地址,指针,指针变量不区分,通称指针
在这里插入图片描述

#include <stdio.h>int main(int argc, const char *argv[])
{//int a = 1;//int *pa = &a;printf("int* = %ld\n",sizeof(int *));printf("char* = %ld\n",sizeof(char *));printf("double* = %ld\n",sizeof(double *));printf("float* = %ld\n",sizeof(float *));printf("long* = %ld\n",sizeof(long *));int a = 1;char ch = 'a';//int *pc = &ch;  //类型不兼容char *pch = &ch;//ch = 'x';*pch = 'x';  //等价于ch = 'x'printf("ch = %c\n",ch);printf("ch = %c\n",*pch);int *pa = &a;printf("%p\n",pch);printf("%p\n",pa);printf("%p\n",pch + 1);  //不同类型的指针,步长不一样printf("%p\n",pa + 1);return 0;
}

5.2指针变量的运算

指针运算是以指针变量所存放的地址量作为运算量而进行运算的。
因此,指针运算的实质就是地址的运算。
指针运算的种类是有限的,它只能进行算术运算,关系运算和赋值运算。

5.2.1 算术运算符

+: px + n 指针向地址大的方向移动n个数据
-: px - n 指针向地址小的方向移动n个数据
++: px++ 指针向地址大的方向移动1个数据
–: px-- 指针向地址小的方向移动1个数据

指针变量加减,表示指针变量向地址大或小的方向移动N个操作空间,两个指针变量相减,表示两个地址之间有多少个操作空间(多少个元素)

【注意】
两个指针做运算,必须是同类型的,类型不同没有任何意义。
一个指针变量加减有意义,乘除没有意义
后置++优先级高于前置++
后置++结合律从左往右
前置++和*优先级相同,结合律从右往左

#include <stdio.h>int main(int argc, const char *argv[])
{int arr[6] = {1,3,5,8,9,10};int *p1 = arr;printf("*p1 = %d\n",*p1);p1++;int *p2 = p1++;printf("*p1 = %d,*p2 = %d\n",*p1,*p2);printf("p1 - p2 = %ld\n",p1 - p2);int y = *p1;  //取值printf("y = %d\n",y);y = ++*p1;printf("y = %d\n",y);y = (*p1)++;printf("y = %d\n",y);y = *p1++;   //赋值完成后,指针px加1printf("y = %d\n",y);printf("*p1 = %d\n",*p1);/*y = ++*p1++;   //赋值完成后,指针px加1printf("y = %d\n",y);printf("*p1 = %d\n",*p1);*/return 0;
}

5.2.2 关系运算符

>     px > py
<
>=
<=
!=
==

两个指针变量可以通过关系运算符来判断保存地址的大小;
两指针之间的关系运算符表示他们指向的地址位置之间的关系,指向地址大的指针大于指向地址小的指针;
具有不同数据类型的指针之间的关系运算没有意义,指向不同数据区域的数据两个指针之间,关系运算符也没有意义;
指针与一般整数变量之间的关系运算也没有意义,但是可以和零进行等于或者不等于的关系运算,判断指针是否为空,一般与NULL。

5.2.3 赋值运算

指针变量直接可以直接赋值,但是不能将一个整数赋值给指针变量,因为没有开辟空间;
指针赋值运算是通过赋值运算符向指针变量送一个地址值。

5.2.4 练习:输入一个字符串,将字符串的元素翻转

要求:定义两个指针,分别保存起始位置和末尾位置的字符,然后通过交换的方式实现。

hello world

dlrow olleh

答案:

#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{char str[32] = {0};gets(str);printf("反转之前的字符串:%s\n",str);char *p = NULL,*q = NULL;char tmp;p = &str[0];q = &str[strlen(str) - 1];
#if 0while(p < q){tmp = *p;*p = *q;*q = tmp;p++;q--;}
#endiffor(;p < q;p++,q--){tmp = *p;*p = *q;*q = tmp;}printf("反转之后的字符串:%s\n",str);return 0;
}

六、指针和一维数组

#include <stdio.h>
#include <string.h>int main(int argc, const char *argv[])
{int a[5] = {1,2,3,4,5};int *p = a;int i;for(i = 0 ; i < 5;i++){//printf("%d ",a[i]);printf("%d ",*(p+i));}putchar(10);char *s = "helloworld";char str[32] ="hello nanjing";s = str;//printf("%s\n",s);for(i = 0 ; i < 10;i++){printf("%c",s[i]);}putchar(10);return 0;
}

练习1:通过指针自己实现strlen函数的功能

#include <stdio.h>int main(int argc, const char *argv[])
{char buf[32] = {0};printf("请输入一个字符串:\n");gets(buf);char *p = buf;int i;while(*p != '\0'){p++;i++;}printf("strlen(buf) = %d\n",i);return 0;
}

练习2: 通过指针实现strcpy函数的功能

#include <stdio.h>int main(int argc, const char *argv[])
{char s1[] = "helloworld!";char s2[] = "abcdefghijk";char *p = NULL,*q = NULL;p = s1;q = s2;while(*q != '\0'){*p = *q;p++;q++;}*p = *q;printf("s1 = %s\n",s1);return 0;
}

作业:

1.通过指针实现strcat功能

2.实现atoi函数的功能

char str[] = '5891";
int num;

“5891” ----->5891

3. 输入一个字符串,输出字符串中有多少个空格

4. 输入两个字符串,判断一个字符串是否为另一个的子串

s1 = hellloworld s2 = oworl