1昨日回顾

const int

和 int const是一样的

const char *p;值不变

char * const p; 指针不能变

编译器对参数的退化:

第三种模型:

三级指针

三级指针局部变量接收二级指针,并改变其内容

2拆分字符串第一种API

#define  _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#include <string.h>

int splitString(char *str,char ch,char array[][30],int *count)

{

char *p = str;

char *q = p;

int temp_count = 0;

int len = 0;

if (str == NULL || array == NULL || count == NULL) {

fprintf(stderr, "str == NULL || array == NULL || count == NULL");

return -1;

}

// 在一个字符串中找到一个字符 找到了 返回第一个字符的地址 失败返回NULL

//strchr(母串,字符)

while (  (p = strchr(p, ch))!= NULL) {

// 找到了

strncpy(array[temp_count], q, p - q);

array[temp_count][p - q] = '\0';

temp_count++;

p++;

q = p;

if (*p == '\0')

{

break;

}

}

if (*q != '\0') {

len = (str + strlen(str)) - q;

strncpy(array[temp_count], q, len);

array[temp_count][len] = '\0';

temp_count++;

}

*count = temp_count;

return 0;

}

int main(void)

{

char *str = "abcdef.acccd.eeee.aaaa.e3eeee.ssss";

char array[10][30];

int count = 0;

int retn = 0;

int i = 0;

retn = splitString(str, ',', array, &count);

if (retn < 0)

{

fprintf(stderr, "splitString er\n");

return -1;

}

for (i = 0; i < count; i++)

{

printf("array[%d]:%s\n", i,array[i]);

}

return 0;

}

3拆分字符串第二种API

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#include <string.h>

int spitString(char *str, char ch,char ***array_p,int *count)

{

// P,q指向str

char *p= str;

char *q = p;

// 计数

int temp_count = 0;

// 二级指针

char **array = NULL;

int str_len = 0;

if (str == NULL || array_p == NULL || count == NULL)

{

fprintf(stderr, "str == NULL || array_p == NULL || count == NULL\n");

return -1;

}

// 1 求出 字符串中 拆分的个数

while ((p = strchr(p, ch)) != NULL) {

temp_count++;

p++;

q = p;

if (*p == '\0') {

// 如果最后一位恰巧是ch那么+1就会是'\0'

break;}

}

// 如果有多余的

if (*q != '\0') {

temp_count++;

}

// 此时temp_count就是子字符串的个数

// 2 根据个数开辟指针数组 在堆上

// 在堆上开辟数组空间

array = (char**)malloc((sizeof(char*) * temp_count));

if (array == NULL)

{

fprintf(stderr, "malloc char **array error\n");

return -1;

}

// 清0

memset(array, 0, sizeof(char *)*temp_count);

// 3 拆分字符串,为每一个指针开辟堆空间 拷贝字符串

p = str;

q = p;

temp_count = 0;

while((p = strchr(p,ch))!= NULL){

// 找到了

str_len = p - q;

// 数组的某个元素指向新分配的堆空间 堆空间大小是 sizeof(char) * str_len +1,+1是为了'\0'

array[temp_count] = (char*)malloc(sizeof(char)*str_len+1);

if (array[temp_count] == NULL)

{

fprintf(stderr, "malloc array[%d] error\n",temp_count);

return -1;

}

// 将值拷贝到堆空间中

strncpy(array[temp_count], q, str_len);

// 最后要增添'\0'

array[temp_count][str_len] = '\0';

// 重复这个过程

temp_count++;

p++;

q = p;

// 如果字符串最后一位恰好是要被替换的ch 那么+1后就会遇到\0

if (*p == '\0')

{

break;

}

}

// 如果字符串最后一位不是ch的情况,q指向不是'\0'

if (*q != '\0') {

str_len = (str + strlen(str)) - q;

array[temp_count] = (char *)malloc(sizeof(char)*(str_len + 1));

// 任何分配空间都要做NULL值错误处理

if (array[temp_count] == NULL) {

fprintf(stderr, "malloc array[%d]error\n", temp_count);

return -1;

}

// 把最后一段复制到array中

strncpy(array[temp_count], q, str_len);

// 结尾补上'\0'

array[temp_count][str_len] = '\0';

// 计数增加

temp_count++;

}

if (array != NULL) {

// 三级指针接数组地址

*array_p = array;

*count = temp_count;

}

return 0;

}

int main(void)

{

char *str = "abcdef,acccd,eeee,aaaa,e3eeee,ssss";

char **array = NULL;

int count = 0;

int retn = 0;

int i = 0;

retn = spitString(str, ',', &array, &count);

for (i = 0; i < count; i++)

{

printf("array[%d]:%s\n", i, array[i]);

}

return 0;

}

3拆分字符串第二种API

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#include <string.h>

void free_mem(char ***array_p,int count) {

char **array = *array_p;

int i = 0;

if (array_p == NULL) {

return;

}

if (array != NULL) {

for (i = 0; i < count; i++) {

if (array[i] != NULL) {

free(array[i]);

array[i] = NULL;

}

}

free(array);

*array_p = NULL;

}

}

int spitString(char *str, char ch,char ***array_p,int *count)

{

// P,q指向str

char *p= str;

char *q = p;

// 计数

int temp_count = 0;

// 二级指针

char **array = NULL;

int str_len = 0;

int retn = 0;

if (str == NULL || array_p == NULL || count == NULL)

{

fprintf(stderr, "str == NULL || array_p == NULL || count == NULL\n");

return -1;

}

// 1 求出 字符串中 拆分的个数

while ((p = strchr(p, ch)) != NULL) {

temp_count++;

p++;

q = p;

if (*p == '\0') {

// 如果最后一位恰巧是ch那么+1就会是'\0'

break;}

}

// 如果有多余的

if (*q != '\0') {

temp_count++;

}

// 此时temp_count就是子字符串的个数

// 2 根据个数开辟指针数组 在堆上

// 在堆上开辟数组空间

array = (char**)malloc((sizeof(char*) * temp_count));

if (array == NULL)

{

fprintf(stderr, "malloc char **array error\n");

retn = -1;

goto END;

}

// 清0

memset(array, 0, sizeof(char *)*temp_count);

// 3 拆分字符串,为每一个指针开辟堆空间 拷贝字符串

p = str;

q = p;

temp_count = 0;

while((p = strchr(p,ch))!= NULL){

// 找到了

str_len = p - q;

// 数组的某个元素指向新分配的堆空间 堆空间大小是 sizeof(char) * str_len +1,+1是为了'\0'

array[temp_count] = (char*)malloc(sizeof(char)*str_len+1);

if (array[temp_count] == NULL)

{

fprintf(stderr, "malloc array[%d] error\n",temp_count);

retn = -1;

goto END;

}

// 将值拷贝到堆空间中

strncpy(array[temp_count], q, str_len);

// 最后要增添'\0'

array[temp_count][str_len] = '\0';

// 重复这个过程

temp_count++;

p++;

q = p;

// 如果字符串最后一位恰好是要被替换的ch 那么+1后就会遇到\0

if (*p == '\0')

{

break;

}

}

// 如果字符串最后一位不是ch的情况,q指向不是'\0'

if (*q != '\0') {

str_len = (str + strlen(str)) - q;

array[temp_count] = (char *)malloc(sizeof(char)*(str_len + 1));

// 任何分配空间都要做NULL值错误处理

if (array[temp_count] == NULL) {

fprintf(stderr, "malloc array[%d]error\n", temp_count);

retn = -1;

goto END;

}

// 把最后一段复制到array中

strncpy(array[temp_count], q, str_len);

// 结尾补上'\0'

array[temp_count][str_len] = '\0';

// 计数增加

temp_count++;

}

if (array != NULL) {

// 三级指针接数组地址

*array_p = array;

*count = temp_count;

}

// 释放内存的步骤

END:

if (retn != 0) {

// 已经出现错误了

free_mem(&array, temp_count);

}

return 0;

}

int main(void)

{

char *str = "abcdef,acccd,eeee,aaaa,e3eeee,ssss";

char **array = NULL;

int count = 0;

int retn = 0;

int i = 0;

retn = spitString(str, ',', &array, &count);

for (i = 0; i < count; i++)

{

printf("array[%d]:%s\n", i, array[i]);

}

free_mem(&array, count);

if (array == NULL) {

printf("arraykong");

}

return 0;

}

4 数组的概念

数组:1. 连续的一大片内存空间

2. 每个元素数据类型相同 (否则不知道该偏移多少

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#include <string.h>

int main(void)

{

int a[10] = { 0 };

int i = 0;

int j = 0;

/*  a是数组名 不能a++,,,,a=a+1;只能a[1]; *(a+i) //数组名是一个常量,是一个常指针,不能够被修改

数组名a本质是指向首元素地址 即&a[0]

a+1 a是int *const p; a+1  4个字节的偏移

&a+1 &a是int[10] *p    &a+1 4*10 = 40个字节的偏移

*/

int aa[3][4] = {

{3,5,4,3},

{2,3,4,5}

};

// 初始化一个数组 不管是几维,如果初始化不完全,剩下的就全部填充0

for (i = 0;i<3;i++)

{

for (j = 0; j < 4; j++)

{

printf("%d", aa[i][j]);

}

printf("\n");

}

printf("\n");

int size = sizeof(aa); //再求一个二维数组的 数据类型大小 int[3][4]

printf("size = %d\n", size);

// 如何定义指针?

// 比较好理解的方法 (int[3][4]) *p = NULL;

// 但是C语言中不能这么写,要把p放在数组前面 下面这样:

int(*p)[3][4] = NULL; // 指向二维数组int[3][4]的指针

printf("p: 0x%p, p+1:0x%p\n", p, p + 1);

// 0x0000 0030 (30是十进制的48)

// 数组也是有数据类型的

return 0;

}

5指针数组和数组指针的概念

typedef unsigned int u32;

int main(void)

{

//unsigned int a;

//u32 b;

//int a[3][4];

int a[10];

//typedef int[10] ARRAY_INT_10; 语法不能这么写,要用下面的写法:

typedef int ARRAY_INT_10 [10]; //为 int[10]这种数组 起一个别名 ARRAY_INT_10

ARRAY_INT_10 b_array; //int b_array[10]

int i = 0;

for (i = 0;i<10;i++)

{

b_array[i] = i;

}

for (i = 0;i<10;i++)

{

printf("%d\n", b_array[i]);

}

ARRAY_INT_10 *p = &b_array;

printf("p:%d,p+1:%d", p, p + 1);

return 0;

}

指针数组:

数组指针:

数组指针的两种定义方式:

6如何定义一个数组指针

void test(){

int aa; //0维数组 一级指针

int aaa[10]; //一维数组,二级指针

int aaaa[10][20]; //二维数组,三级指针

int a[3][4];

// a是一个指针 指向此二维数组首元素int[4]地址  int (*p)[4] == 二级指针 指向一维数组

// &a也是一个指针 指向此二维数组int[3][4]的地址 int(*p)[3][4] == 三级指针 指向一个二维数组

// 推论:一个数组指针,如果是几级指针,就是指向比他低一个维度的数组。

}

int main(void)

{

// 定义一个指针数组

// 在栈上  用char* 还是void*都是一样的四个长度

char *pinter_array[4] = { "asd",NULL,NULL,NULL };

// 在堆上:

char *heap_array =  malloc( 4 * sizeof(char*));

for(int i = 0;i<4;i++)

{

heap_array[i] = NULL;

}

int i = 0;

// 定义一个数组指针

// 方法一

// 直接定义一个数组类型

typedef int (ARRAY_CHAR_4) [4];

ARRAY_CHAR_4 array = { 1,2,3,4 };

ARRAY_CHAR_4 *p = NULL;

p = &array;

//方法二

typedef int (*ARRAY_CHAR_4_POINTER) [4];

ARRAY_CHAR_4_POINTER array_pointer = &array;

// 方法三

int(*array_p)[4] = NULL; // 直接定义一个数组指针

array_p = &array;

return 0;

}

7中午回顾

1这个算法: 用两个指针

2.养成好习惯:

free之后一定要 null

如果是NULL就return

free函数的返回值是void 所以不知道有没有成功,

自己接收的时候一定要用null来判断一下

8多维数组做为函数参数

(编译器并不是在栈中拷贝一份数组)

(并不是这样,否则太浪费空间了)

结论:当数组作为函数参数的时候,会退化成指针

形参用了数组的元素的指针来接收数组

(因为用了数组元素指针,就可以任意索引遍历数组

(数组作为形参被编译器退化)

。。。

补充:

总结:

9指针数组的练习

// 数组无论是几维数组 都是一块连续的内存空间

10main函数的命令行参数

判断数组长度了 除了 sizeof(p)/sizeof(*p) 这种方法,

还有一种方法:

就是在数组最后加一个NULL

然后for循环,

for(i = 0; arr[i] !=NULL;i++)

{

// 遍历

}

main函数入口的第三个参数是char *env[]

(前两个是int argc,char* argv

env指针数组就是这样实现的,最后一项默认是NULL

所以可以打印出来:

(环境变量:进程共享的变量

在windows运行桌面上的应用程序时候其实就是相当于在cmd里输入….exe 可执行程序可以拿到环境变量,环境变量是key value值的形式,value值是一段字符串

C语言提高 (4) 第四天 数组与数组作为参数时的数组指针的更多相关文章

  1. 数组名作为函数参数以及sizeof用法

    来源:https://blog.csdn.net/jay_zhouxl/article/details/51745518 int f(int *p,char *a) { printf("p[ ...

  2. GO语言学习(十四)Go 语言数组

    Go 语言数组 Go 语言提供了数组类型的数据结构. 数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形.字符串或者自定义类型. 相对于去声明number0 ...

  3. C语言提高 (3) 第三天 二级指针的三种模型 栈上指针数组、栈上二维数组、堆上开辟空间

    1 作业讲解 指针间接操作的三个必要条件 两个变量 其中一个是指针 建立关联:用一个指针指向另一个地址 * 简述sizeof和strlen的区别 strlen求字符串长度,字符数组到’\0’就结束 s ...

  4. Android JNI编程(四)——C语言多级指针、数组取值、从控制台输入数组

    版权声明:本文出自阿钟的博客,转载请注明出处:http://blog.csdn.net/a_zhon/. 目录(?)[+] 一:前面我们介绍了一级指针的相关概念和用发,今天我们就来说一说多级指针. 1 ...

  5. c语言提高第二天

    一.指针强化1.指针也是一种数据类型,指针变量也是一种变量,和int a本质是一样的 1)指针变量也是一种变量,也有空间,32位程序大小为4个字节 int *p = 0x1122; 2)*操作符,*相 ...

  6. c语言提高篇 第一天

    一.听课标准 1.选择法排序 2.会简单封装函数 3.数组做函数参数会退化为一级指针 a.数组做函数参数时,应该吧数组元素个数也传递给函数 b.形参中的数组,编译器把它仿作指针处理,c语言特色 c.实 ...

  7. Swift5 语言指南(二十四) 泛型

    通用代码使您能够根据您定义的要求编写可以使用任何类型的灵活,可重用的函数和类型.您可以编写避免重复的代码,并以清晰,抽象的方式表达其意图. 泛型是Swift最强大的功能之一,Swift标准库的大部分内 ...

  8. C语言高速入门系列(四)

    C语言高速入门系列(四) C语言数组 ---------转载请注明出处:coder-pig 贴心小提示:假设图看不清晰可右键另存为,应该就非常清晰了; 注意上面的代码都要自己过一遍哦! 本节引言: 经 ...

  9. 《C语言程序设计(第四版)》阅读心得(一)

    本篇开始写我个人觉得谭浩强老师的<C语言程序设计(第四版)>中之前没有认识到,或者忘了的知识.因为本科学过,所以有些简单的东西就没有放进来了,所以可能并不是太全面. 第一章程序设计与语言 ...

随机推荐

  1. orcale 日期显示格式化

    SQL> select * 2 from emp 3 where hiredate='1987-11-17'; where hiredate='1987-11-17' * 第 3 行出现错误: ...

  2. 1009在WINDOWS上面如何备份数据库

    第一步 解决windows上面使用GZIP命令 参考http://www.xuebuyuan.com/1676976.html 后经研究,发现解决方法也很简单,只需下载gzip的windows版本,解 ...

  3. [bzoj1606][Usaco2008 Dec]Hay For Sale 购买干草_动态规划_背包dp

    Hay For Sale 购买干草 bzoj-1606 Usaco-2008 Dec 题目大意:约翰遭受了重大的损失:蟑螂吃掉了他所有的干草,留下一群饥饿的牛.他乘着容量为C(1≤C≤50000)个单 ...

  4. POJ 1198/HDU 1401

    双向广搜... 呃,双向广搜一般都都用了HASH判重,这样可以更快判断两个方向是否重叠了.这道题用了双向的BFS,有效地减少了状态.但代码太长了,不写,贴一个别人的代码.. #include<i ...

  5. 王立平--Http中Get() 与 Post()的差别?

    Http协议是基于TCP协议的,而TCP协议是一种有连接.可靠的传输协议.假设丢失的话,会重传.所以这种话,就 不会有数据的丢失了. 而Http协议有三种方法.Get,Post,Head方法.可是用的 ...

  6. Centos6.2中配置tomcat

    这里我使用的是tomcat6, 我使用的是server版本号的Centos, 前提是安装而且配置好了JDK. 首先通过samba把我的tomcat压缩包, 复制到了共享的文件夹.然后移动到./usr文 ...

  7. cocos2d函数

    CCNodeLoader::parseProperties CCBReader::readNodeGraph kCCBPropTypeBlockCCControl CCInvocation parse ...

  8. Web端即时通讯、消息推送的实现

    https://blog.csdn.net/DeepLies/article/details/77726823

  9. leetcode解题文件夹

    点击打开链接点击打开链接点击打开链接參考文献:http://blog.csdn.net/lanxu_yy/article/details/17848219 只是本文准备用超链接的方式连接到对应解答页面 ...

  10. 【待解决】创建maven web工程报错

    报错信息如下: Could not calculate build plan: Plugin org.apache.maven.plugins:maven-resources-plugin:2.6 o ...