黑马程序员——C语言学习之数组——字符串——指针

来源:互联网 发布:手机浏览器启动淘宝 编辑:程序博客网 时间:2024/06/05 23:49

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

数组

一、数组的基本概念

1. 什么是数组

数组,从字面上看,就是一组数据的意思,没错,数组就是用来存储一组数据的

 

2. 数组的特点

1> 只能存放一种类型的数据,比如int类型的数组、float类型的数组

2> 里面存放的数据称为“元素”

 

二、数组的定义

1. 定义

想要定义一个数组,需要声明两点:

声明数组的类型

声明数组的元素个数(需要多少存储空间)

 

2. 格式

元素类型 数组名[元素个数];

比如:

int a [3];

 

3. 初始化

1> 初始化方式

int a[3] = {10, 9, 6};int a[3] = {10,9};int a[] = {11, 7, 6};int a[4] = {[1]=11,[0] = 7};

 

2> 常见错误

int a[];int[4] a;int a[b];a = {10, 11};a[4] = {10,9,8,5};

 

4>一维数组作为函数参数

数组名代表着整个数组的地址,如果一维数组的名字作为函数实参,传递的是整个数组,这样形参数组修改时,实参数组也同时被修改了。形参数组的元素个数可以省略。

 

三、二维数组

1> 二维数组的定义

其实二维数组就相当于装着一维数组的一维数组。

定义形式:

类型  数组名[行数][列数]

例如:

int a[2][3]; // 共2行3列,6个元素

 

2>二维数组的初始化

1> 按行进行初始化

int a[2][3] = { {2, 2, 3}, {3, 4, 5} };


2> 按存储顺序进行初始化(先存放第1行,再存放第2行)

int a[2][3] = {2, 2, 3, 3, 4, 5};


3> 对部分元素进行初始化

int a[2][3] = { {2}, {3, 4} };int b[3][3] = { { }, { , , 2}, {1, 2, 3}};

 

4> 如果只初始化了部分元素,可以省略行数,但是不可以省略列数

<strong>int a[][3] = {1, 2, 3, 4, 5, 6};int a[][3] = {{1, 2, 3}, {3, 5}, {}};</strong>

 

写在最后:
有些人可能想不明白,为什么可以省略行数,但不可以省略列数。也有人可能会问,可不可以只指定行数,但是省略列数?其实这个问题很简单,如果我们这样写:

int a[2][] = {1, 2, 3, 4, 5, 6}; // 错误写法

大家都知道,二维数组会先存放第1行的元素,由于不确定列数,也就是不确定第1行要存放多少个元素,所以这里会产生很多种情况,可能1、2是属于第1行的,也可能1、2、3、4是第一行的,甚至1、2、3、4、5、6全部都是属于第1行的

 

字符串

一、字符串

字符串可以看做是一个特殊的字符数组,并在字符串的尾部添加了一个结束标志 '\0'。

 

1. 字符串的初始化

// ‘\0’的ASCII码值是0    // 都是字符串    char name[5] = "it";    char name2[5] = {'i', 't', '\0'};    char name3[5] = {'i', 't', 0};    char name4[5] = {'i', 't'};    char name5[5];    name5[0] = 'i';    name5[1] = 't';    name5[2] = 0;    name5[3] = 0;    name5[4] = 0;       // 不算是一个字符串(只能说是一个字符数组)    char name6[] = {'i', 't'};

 

2. printf函数

printf函数在输出字符串的时候会从所给的字符串地址开始输出,直到遇到 '\0' 时结束输出。如下:

    char name[20] = "helloworld\0welcome";    printf("%s\n", name);printf("%s\n", &name[3]);

 

输出:

helloworldloworld

 

分析:

printf 函数在输出字符串时,接收的是字符串的地址。
printf("%s\n", name); 
中的name其实是name[20]数组中的首地址,和&name[0]同一意思,所以从name[0]开始输出,直到'\0'时结束。
printf("%s\n", &name[3]);
也是一样的,从name[3]的位置开始输出,直到 '\0'时结束。

 

3. strlen函数

1> 计算的字符不包括 '\0'
2> 计算的是字符数,并不是字数。一个汉字算作3个字符
3> 从某个地址开始数字符的个数,直到遇到 '\0' 为止


例如:

    int len = strlen("hello");     int len2 = strlen("helloćˆ‘");       int len3 = strlen("hello\0world");     printf("%d\n", len);    printf("%d\n", len2);printf("%d\n", len3);

输出:

585

 

分析:
应用1、2、3点就可以理解了

 

二、字符串数组

1. 使用场合

1> 一维字符数组中存放一个字符串,比如一个名字char name[20] = "mj"

2> 如果要存储多个字符串,比如一个班所有学生的名字,则需要二维字符数组,char names[15][20]可以存放15个学生的姓名(假设姓名不超过20字符)

3> 如果要存储两个班的学生姓名,那么可以用三维字符数组char names[2][15][20]

 

2. 初始化

char names[2][10] = { {'J','a','y','\0'}, {'J','i','m','\0'} }; char names2[2][10] = { {"Jay"}, {"Jim"} }; char names3[2][10] = { "Jay", "Jim" }; 

指针

一、什么是指针?

指针是用来存放变量地址的。通过指针可以间接操纵变量。

 

二、指针的定义

变量类型 *变量名;

如:int *p;定义了一个int类型的指针p。
注意:任何类型的指针都占据8个字节的存储空间

 

三、指针的初始化

1. 先定义,后初始化

int a = 10; // 定义变量a   intint *p;     // 定义int型指针p   p = &a;     // 给指针p赋值,存放的是变量a的存储地址 

 

2. 定义的同时初始化

int a = 10;      // 定义变量a   intint *p = &a;     // 定义int型指针p,同时给指针p赋值,存放的是变量a的存储地址  

 

四、指针的使用

1. 取出指向变量的值

int a = 10;        intint *p = &a;       int value = *p;   // 访问指针p所指向的变量a的值,并赋值个value,value = 10;  

 

2、给指针指向的变量赋值

int a = 10;        intint *p = &a;       *p = 20;         // 指针p所指向的变量的值被改成20,也就是a的值被改成20  

 

的含义:
int *p = &a 中的 * 用来说明 p 是一个指针类型的变量,和变量类型是一个整体。
*p 中得 * 用来访问 p 所指向的变量a

3. 使用注意

在指针指向变量之前,不要对其所指的内容赋值。因为此时指针指向的地址不确定。如下是错误的:

intint *p;       *p = 10;  

 

五、指针与数组

1. 基本使用

数组名就是数组的地址,也是数组首元素的地址,既然是地址,也就可以赋值给指针变量。

int values[5] = {10, 9, 8, 67, 56};  intint *p = values;  intint *p2 = &values[0];    printf("%p\n", p);  printf("%p\n", p2);      int values[5] = {10, 9, 8, 67, 56};    int *p = values;    int *p2 = &values[0];       printf("%p\n", p);    printf("%p\n", p2);


输出:

0x7fff549f2c600x7fff549f2c60

 

2、利用指针来访问数组元素

1> int values[5] = {10, 9, 8, 67, 56};  intint *p = values;  // 数组方式   for (int i = 0; i < sizeof(values) / sizeof(int); i++) {      printf("values[%d] = %d\t", i, values[i]);  }    printf("\n");    // 数组访问方式1   for (int i = 0; i < sizeof(values) / sizeof(int); i++) {      printf("values[%d] = %d\t", i, p[i]);  }    printf("\n");  // 数组访问方式2   for (int i = 0; i < sizeof(values) / sizeof(int); i++) {      printf("values[%d] = %d\t", i, *(p + i));  }      int values[5] = {10, 9, 8, 67, 56};    int *p = values;    // 数组方式    for (int i = 0; i < sizeof(values) / sizeof(int); i++) {        printf("values[%d] = %d\t", i, values[i]);    }     printf("\n");       // 数组访问方式1    for (int i = 0; i < sizeof(values) / sizeof(int); i++) {        printf("values[%d] = %d\t", i, p[i]);    }     printf("\n");    // 数组访问方式2    for (int i = 0; i < sizeof(values) / sizeof(int); i++) {        printf("values[%d] = %d\t", i, *(p + i));    }

 

输出:

values[0] = 10values[1] = 9values[2] = 8values[3] = 67values[4] = 56values[0] = 10values[1] = 9values[2] = 8values[3] = 67values[4] = 56values[0] = 10values[1] = 9values[2] = 8values[3] = 67values[4] = 56

 

注意:
*(p + 1);表示把指针指向的地址移到下一个该变量类型的地址

同理,*(p + i);表示在p指向的地址的基础上,把指针指向的地址移到第 i 个该变量类型的地址

3. 传递

数组作为参数传递给函数的本质是把数组的地址传递给函数

void test(int v[])  {      printf("大小:%lu\n", sizeof(v));      printf("地址:%p\n", v);  }    int main()  {      int values[5] = {10, 9, 8, 67, 56};      printf("大小:%lu\n", sizeof(values));      printf("地址:%p\n", values);            test(values);        return 0;  }  void test(int v[]){    printf("大小:%lu\n", sizeof(v));    printf("地址:%p\n", v);} int main(){    int values[5] = {10, 9, 8, 67, 56};    printf("大小:%lu\n", sizeof(values));    printf("地址:%p\n", values);       test(values);     return 0;}

 

输出:

大小:20地址:0x7fff55dc6c60大小:8地址:0x7fff55dc6c60

 

六、指针与字符串

字符串的本质是字符数组,所以字符串的名字也就是第一个字符的地址,也是字符串的地址。

1. 定义

之前定义字符串的方式是:

char name[] = "itcast";      char name[] = "itcast";

 

有了指针后,可以:

charchar *name = "itcast";      char *name = "itcast";

 

2. 区别

1> 字符数组方式

    特点:字符串里面的字符是可以修改的

    使用场合:字符串的内容需要经常修改

2> 指针方式

    特点:字符串其实是一个常量字符串,里面的字符是不能修改

    使用场合:字符串的内容不需要修改,而且这个字符串经常使用

 

七、清空指针

假设p是任意的指针。清空指针的值方式如下:

p = 0;      p = NULL;  

 

八、为什么int类型的指针只能指向int类型的变量

1. 例子

先看下面的程序:

int i = 2;  char c = 1;  // int类型的指针指向char类型的变量   intint *p = &c;  printf("%d", *p);      int i = 2;    char c = 1;    // int类型的指针指向char类型的变量    int *p = &c;    printf("%d", *p);

 

输出结果:

513

 

2. 内存分析

仿照MJ老师画了一张图,
由于p是int类型的指针,指向的地址是 ffc1,于是就从 ffc1 取出四个字节的内容来:0000 0000 0000 0000 0000 0010 0000 0001,换算成十进制就是513,这就是int类型的指针为什么不能指向char类型的变量的原因。


总结:同种类型的指针只能指向同种类型的变量

 

九、函数和指针

1. 返回指针的函数

定义格式:

数据类型 *函数名(参数列表){// ...}

 

如:

charchar *pChar()  {      return "hello";  }  

 

2、指向函数的指针

定义格式:

数据类型 (*pointName)(参数列表);


如:

void test()  {      printf("调用了test函数\n");  }    int sum(int a, int b)  {      return a + b;  }    int main()  {      int (*p)(int, int); // 定义       p = sum;            // 初始化       int c = p(10, 11);  // 调用函数,相当于sum(10, 11);       printf("c is %d\n", c);            void (*p2)() = test; // 定义的同时初始化       p2();               // 调用函数             return 0;  }  



0 0
原创粉丝点击