第5天 C语言数组和字符串

    科技2024-12-29  20

    数组名

    数组名代表数组首元素的地址,它是个常量。数组首元素的地址和数组地址是两个不同的概念。变量本质是内存空间的别名,一定义数组,就分配内存,内存就固定了。所以数组名起名以后就不能被修改了。 数组首元素的地址和数组的地址值相等。 怎么样得到整个一维数组的地址?

    int a[10]; printf("得到整个数组的地址a: %d \n", &a); printf("数组的首元素的地址a: %d \n", a);

    数组类型

    int a[] = { 1, 3, 5 }; //3个元素 a: 数组首行首元素地址,一级指针 &a: 整个数组的首地址,二级指针 首行首元素地址和首行(整个一维数组)地址值虽然是一样,但是它们的步长不一样 a+1: 跳过1元素,一元素为4字节,步长4个字节 &a+1: 跳过整个数组,整个数组长度为 3*4 = 12,步长 3 * 4 = 12 sizeof(a): 传参为:数组首行首元素地址,测数组(int [3])的长度,3 * 4 = 12 sizeof(a[0]): 传参为:数组首元素(不是地址),每个元素为int类, 4字节 sizeof(&a):传参为:一维数组整个数组的地址(首行地址),编译器当做指针类型,4字节 (重要)首行地址 --> 首行首元素地址(加*) &a:首行地址 *&a -> a : 首行首元素地址 //数组也是一种数据类型,类型本质:固定大小内存块别名 //由元素类型和内存大小(元素个数)共同决定 int a[5] int[5] //可以通过typedef定义数组类型 //有typedef:类型 //没有typedef:变量 typedef int ARRARY[5]; //定义了一个名字为ARRARY的数组类型 //等价于typedef int (ARRARY)[5]; //根据数组类型,定义变量 //ARRARY的位置替代为d,去掉typedef,int d[5] ARRARY d; //相当于int d[5]; 基本数据类型大小x数组元素个数=数组大小 数组的类型由元素类型和数组大小共同决定 int array[5] 的类型为 int[5];

    一维数组的初始化

    int a[] = { 1, 3, 5 }; //3个元素 int b[5] = { 1, 2, 3 }; //a[3], a[4]自动初始化为0 int c[10] = { 0 }; //全部元素初始化为0 memset(c, 0, sizeof(c)); //通过memset给数组每个元素赋值为0

    多维数组

    1)二维数组初始化 int a1[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} }; int a2[3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; int a3[][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; 2)内存中并不存在多维数组,多维数组在内存中都是线性存储 int a[3][5] = { 0 }; int *b = (int *)a; int i = 0; for(i = 0; i < 15; i++) { printf("%d ", b[i]); } 3)多维数组名 //学会类比 int b[5] = {0}; b: 首行首元素地址, +1,跳 4 个字节 &b:首行地址,+1,跳 4*5 = 20个字节 //二维数组实际上就是 N 个一维数组 //把二维数组第一个[]的值看做标志位,0 -> 2 //第0个一维数组a[5] -> 第2个一维数组a[5] int a[3][5] = { 0 }; a: 二维数组首元素地址 代表首行地址,相当于一维数组整个数组的地址,相当于上面的 &b,本来就是一个二级指针 //(重要)首行地址 --> 首行首元素地址(加*) *a:首行首元素地址,相当于一维数组首元素地址,相当于上面的 b a + i -> &a[i]: 第i行地址 //(重要)某行地址 --> 某行首元素地址(加*) *(a+i) -> *&a[i] -> a[i]: 第i行首元素地址 //第i行j列元素的地址,某行首元素地址 + 偏移量 *(a+i)+j -> a[i]+j -> &a[i][j]: 第i行j列元素的地址 //第i行j列元素的值,第i行j列元素的地址的基础上(加 *) *(*(a+i)+j) -> a[i][j]: 第i行j列元素的值 int a[3][5] = { 0 }; sizeof(a): 二维数组整个数组长度,4 * 3 * 5 = 60 sizeof(a[0]):a[0]为第0行首元素地址,相当于测第0行一维数组的长度:4 * 5 = 20 sizeof(a[0][0]):a[0][0]为第0第0列元素(是元素,不是地址),测某个元素长度:4字节 4)多维数组名,实际上是一个数组指针,指向数组的指针,步长为一行字节长度 int a[3][5] = { 0 }; //定义一个数组指针类型的变量 int(*p)[5]; //编译会有警告,但不会出错,因为 a 和 &a的值一样 //但是&a代表整个二维数组的首地址 //就算p = &a这样赋值,编译器内部也会自动转换为 p = a //不建议这么做 p = &a; //a 本来就是第0个一维数组整个数组的地址,所以,无需加& p = a; 5)二维数组做形参的三种形式 //一维数组做函数参数退化为一级指针 //二维数组(多维数组)做函数参数,退化为数组指针 int a[3][5] = { 0 }; void print_array1(int a[3][5]); //第一维的数组,可以不写 //第二维必须写,代表步长,确定指针+1的步长 5*4 void print_array2(int a[][5]) //形参为数组指针变量,[]的数字代表步长 void print_array3(int (*a)[5]); //a+1和二维数组的步长不一样 //这里的步长为4 //上面二维数组的步长为 5 * 4 = 20 void print_array3(int **a); //err

    字符数组初始化方法

    #include <stdlib.h> #include <string.h> #include <stdio.h> //一级指针的典型用法 //字符串 //1 C语言的字符串 以零'\0'结尾的字符串 //2 在C语言中没有字符串类型 通过字符数组 来模拟字符串 //3 字符串的内存分配 堆上 栈上 全局区 //字符数组 初始化 int main() { //1 不指定长度 C编译器会自动帮程序员 求元素的个数 char buf1[] = {'a', 'b', 'c', 'd'}; //buf1是一个数组 不是一个以0结尾的字符串 //2 指定长度 char buf2[100] = {'a', 'b', 'c', 'd'}; //后面的buf2[4]-buf2[99] 个字节均默认填充0 //char buf3[2] = {'a', 'b', 'c', 'd'}; //如果初始化的个数大于内存的个数 编译错误 printf("buf1: %s\n", buf1); printf("buf2: %s \n", buf2); printf("buf2[88]:%d \n", buf2[88]); //3 用字符串初始化 字符数组 char buf3[] = "abcd"; //buf3 作为字符数组 有5个字节 // 作为字符串有 4个字节 int len = strlen(buf3); printf("buf3字符的长度:%d \n", len); //4 //buf3 作为数组 数组是一种数据类型 本质(固定小大内存块的别名) int size = sizeof(buf3); // printf("buf3数组所占内存空间大小:%d \n", size); //5 char buf4[128] = "abcd"; // buf printf("buf4[100]:%d \n", buf4[100]); return 0; }

    数组法和指针法操作字符串

    #include <stdio.h> #include <string.h> int main(void) { int i = 0; char *p = NULL; char buf[128] = "abcdefg"; //通过[] for (i=0; i<strlen(buf); i++) { printf("%c ", buf[i]); } p = buf; //buf 代表数组首元素的地址 //通过指针 for (i=0; i<strlen(buf); i++) { printf("%c ", *(p+i) ) ; } // [] 的本质 和 *p 是一样。 //通过数组首元素地址 buf 来操作 for (i=0; i<strlen(buf); i++) { printf("%c ", *(buf+i) ) ; } /*buf 是一个指针,只读的常量。之所以buf是一个常量指针是为了释放内存的时候,保证buf所指向的内存空间安全。 */ return 0; }

    字符串做函数参数

    #include <stdlib.h> #include <string.h> #include <stdio.h> int main(void) { char a[] = "i am a student"; char b[64]; int i = 0; for (i=0; *(a+i) != '\0'; i++) { *(b+i) = *(a+i); } //0没有copy到b的buf中. b[i] = '\0'; //重要 printf("a:%s \n", a); printf("b:%s \n", b); return 0; }

    字符串拷贝函数的实现

    ```handlebars #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> int main01(void) { char src[] = "abcedfdgds"; char dst[100] = { 0 }; int i = 0; for (i = 0; src[i] != '\0'; i++) { dst[i] = src[i]; } //补结束符 dst[i] = 0; printf("%s\n", dst); printf("\n"); system("pause"); return 0; } void my_strcpy(char *dst, char *src) { int i = 0; for (i = 0; *(src+i) != '\0'; i++) { *(dst+i) = *(src+i); //dst[i] = src[i] } //补结束符 //dst[i] = 0; *(dst + i) = 0; } void my_strcpy2(char *dst, char *src) { while (*src != 0) { *dst = *src; dst++; src++; } *dst = 0; } void my_strcpy3(char *dst, char *src) { //*dst = *src //dst++, src++ //判断 *dst是否为0, 为0跳出循环 while (*dst++ = *src++) { NULL; } } //成功为0,失败非0 //1、判断形参指针是否为NULL //2、最好不要直接使用形参 int my_strcpy4(char *dst, char *src) { if (dst == NULL || src == NULL) { return -1; } //辅助变量把形参接过来 char *to = dst; char *from = src; //*dst = *src //dst++, src++ //判断 *dst是否为0, 为0跳出循环 while (*to++ = *from++) { NULL; } printf("my_strcpy4: dst = %s\n", dst); return 0; } int main(void) { char src[] = "abcedfdgds"; char dst[100] = { 0 }; int ret = 0; ret = my_strcpy4(dst, src); if (ret != 0) { printf("my_strcpy4 err:%d\n", ret); return ret; } printf("%s\n", dst); printf("\n"); system("pause"); return 0; } 希望关注点赞评论,传递知识 想要关注我一起学习的请关注公众号:莫林的日常 想要和志同道合的伙伴一起学习的请加QQ群:515271405
    Processed: 0.009, SQL: 8