c提高1

数据类型

数 据 类 型 { 简 单 类 型 { 基 本 类 型 { 整 型 ( i n t ) 浮 点 型 ( f l o a t , d o u b l e ) 字 符 型 ( c h a r ) 空 类 型 ( v o i d ) 用 户 基 本 类 型 枚 举 类 型 ( e n u m ) 结 构 类 型 { 数 组 ( [   ] ) 结 构 ( s t r u c t ) 联 合 ( u n i o n ) 类 ( c l a s s ) 指 针 类 型 ( ∗ ) 数据类型 \begin{cases} 简单类型 \begin{cases} 基本类型 \begin{cases} 整型 (int) \\浮点型(float,double) \\字符型(char) \\空类型 (void) \end{cases}\\ \\用户基本类型 \quad 枚举类型(enum) \end{cases}\\ \\结构类型 \begin{cases} 数组([\ ]) \\结构(struct) \\联合(union) \\类(class) \end{cases}\\ \\指针类型 (*) \end{cases}\\ (int)float,doublechar(void)enum[ ]structunionclass

数据类型本质:固定内存大小的别名。

c++通过引用可以对同一块内存起多个别名

函数是一种特殊的数据类型.

数组类型

c语言3大难点

  1. 定义一个数组类型
  2. 定义一个数组指针
  3. 数组类型和数组指针关系

数组做函数参数会退化为指针,正确做法是传递数组内存首地址和数组有效长度。这是c的特色之一。

数组元素个数:
n = sizeof(a) / sizeof(a[0])

//或者事先宏定义:

#define DIM(a) (sizeof(a) / sizeof(*a))

n = DIM(a);

//但函数中的多维数组要注意指针退化问题,n会变为4/4.

int a[]
a代表首元素地址;
&a代表整个数组的地址。

不存在void类型的变量,因为编译器不知道如何分配内存。
void*可以指向任何类型的地址。

  • 作为左值用于接收任何类型的指针
  • 作为右值赋值给其它指针时需要强制类型转换。

赋值

直接复制和间接赋值。

间接赋值举例:*(int *)0x1234 = 1,相当于直接修改内存。

变量三要素

名称,大小,作用域。


内存四区

代码区,全局区,堆,栈。

由编译器自动分配和释放,存储函数得参数,局部变量等。

函数返回局部变量(临时变量)的地址时会出现warning或者宕机,releasedebug模式结果不一样。

main函数调用func函数:

| func()参数     |
|----------------|
| func()返回地址  |
|----------------|
| main()运行状态  |
|----------------|  <-----执行func()
| main()参数     |
|----------------|
| main()返回地址  |
|----------------|
| 操作系统运行状态 |
|-----------------|

由程序员分配和释放。

全局区

存储全局变量和静态变量,程序结束后由os释放。

代码区

存储二进制代码。


指针

c语言两大江山:

  • 多级指针
  • 函数指针

指针也是种数据类型,与指向的内存空间的数据类型相关,指针步长由该类型决定。

一级指针可参考c字符串部分

二级指针传送门

p + p没有意义;

p - p有意义.

野指针

/*
	注意野指针问题
	释放空间,但没有重置指针。
	避免方法:指针初始化时和释放后及时置为NULL。
*/
if(p != NULL)
{
    free(p);
    //p = NULL;
}

间接赋值

利用指针进行间接赋值,是指针的意义所在,是C的最大特色。

3个条件:

  1. 定义指针p和要指向的数据data
  2. p = &data
  3. *p间接修改data

输入输出特性

in: 主调函数分配内存传给被调函数。

out:被调函数分配内存传给主调函数。

const

const char *p;,修饰内存空间;

char* const p,修饰指针。

malloc()

搭配malloc()使用时,切记要free()

其实,malloc()在实际项目中不能轻易使用。

真正应该使用该函数的情况是,在函数中分配的空间在函数结束后还需要存在。

指针参数

函数有指针参数,切记先判断指针是否为NULL。!!!!!!!!!!!!!!!!!!


C字符串

  • '\0'结尾
  • 用字符数组模拟
  • 可分配在栈上、堆上和全局区

初始化

1. 指定长度

char s[100] = {'a','b','c','d'};
其余自动置为0

2.不指定长度

char s[] = {'a','b','c','d'};
编译器自动求元素个数;
不以0结尾;

3.用字符串初始化数组

char s[] = "abc";

以0结尾
作为数组,长度为4,即sizeof()
作为字符串,长度为3,即strlen()

指针操作字符串

中括号[]到星号*的推导过程:

char s[];
s[i]–>s[0+i]–>*(s+i)

区别:s是只读的常量地址,而指针可变。

/*
	字符串copy
*/
//假设dest和src都开辟了内存
while( (*dest = *src) != '\0')
{
    src++;
    dest++;
}
while( (*dest++ = *src++) != '\0')
{}
while( (*dest++ = *src++) );

一级指针内存模型

char s[] = "aaa";
"aaa"位于全局区和栈区。

char *p1 = "bbb";
全局区。

char *p2 = (char*)malloc(10);
strcpy(p2,"ccc");
"ccc"位于全局区和堆区。

二级指针

第一种模型

全局区

#include<stdio.h>
#include<string.h>

void print(char **a,int n)
{
	int i = 0;
	for(i = 0; i < n; i++)
	{
		printf("%s\n",*(a+i));
	}
}
void sort(char **a,int n)
{
	int i,j;
	char *tmp = NULL; 
	for(i = 0; i < n; i++)
	{
		for(j = i + 1; j < n; j++)
		{
			if(strcmp(a[i],a[j]) > 0)
			{
				tmp = a[i];
				a[i] = a[j];
				a[j] = tmp;
			}
		}
	}
}
int main(int argc, char *argv[])
{
	char *a[] = {
		"bbb","ccc","aaa"
	};
	int n = sizeof(a) / sizeof(a[0]); //  12/4
	print(a,n);
	sort(a,n);
	printf("  after sort():\n");
	print(a,n);
	
	return 0;
}

第二种模型

栈区

#include<stdio.h>
#include<string.h>

void print(char a[5][10],int n)
{
	int i = 0;
	for(i = 0; i < n; i++)
	{
		printf("%s\n",*(a+i));
	}
}
void sort(char a[5][10],int n)
{
	int i,j;
	char tmp[10] = {0}; 
	
	for(i = 0; i < n; i++)
	{
		for(j = i + 1; j < n; j++)
		{
			if(strcmp(a[i],a[j]) > 0)
			{
				strcpy(tmp,a[i]);
				strcpy(a[i],a[j]);
				strcpy(a[j],tmp);
			}
		}
	}
}
int main(int argc, char *argv[])
{
	char a[5][10] = {
		"bbb","ccc","aaa"
	};
	int n = sizeof(a) / sizeof(a[0]);  //  row : 50/10 != 3
	printf("%s",a[4]);
	print(a,n);
	sort(a,n);
	printf("  after sort():\n");
	print(a,n);
	
	return 0;
}

第三种模型

堆区.

这种模型一定要写得健壮,及时释放内存。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int getMem(char ***s,int n);
void print(char **a,int n);
void sort_point(char **a,int n);
void sort_mem(char **a,int n);
void freeMem(char ***buf,int n);
int getMem(char ***s,int n)
{
	char **a = NULL;
	int i;
	if(s == NULL)
	{
		perror("s can't be NULL.");
		return -1;
	}
	a = (char**)malloc(n * sizeof(char*));
	
	if(a == NULL)
	{
		perror("malloc() error.");
		return -1;
	}
	memset(a,0,n * sizeof(char*));
	for(i = 0; i < n; i++)
	{
		a[i] = (char*)malloc(10);
		if(a[i] == NULL)
		{
			perror("malloc() error.");
			freeMem(&a,n);
			return -1;
		}
		snprintf(a[i],10,"%c%c%c",i+65,i+65,i+65);
	}
	*s = a;
	return 0;
}

void print(char **a,int n)
{
	int i = 0;
	for(i = 0; i < n; i++)
	{
		printf("%s\n",*(a+i));
	}
}
void sort_point(char **a,int n)
{
	int i,j;
	char *tmp = NULL; 
	
	for(i = 0; i < n; i++)
	{
		for(j = i + 1; j < n; j++)
		{
			if(strcmp(a[i],a[j]) < 0)
			{
				tmp = a[i];
				a[i] = a[j];
				a[j] = tmp;
			}
		}
	}
}
void sort_mem(char **a,int n)
{
	int i,j;
	char tmp[10] = {0}; 
	
	for(i = 0; i < n; i++)
	{
		for(j = i + 1; j < n; j++)
		{
			if(strcmp(a[i],a[j]) > 0)
			{
				strcpy(tmp,a[i]);
				strcpy(a[i],a[j]);
				strcpy(a[j],tmp);
			}
		}
	}
}
void freeMem(char ***buf,int n)
{
	char **p = NULL;
	int i;
	if(buf == NULL)
	{
		return ;
	}
	p = *buf;
	
	if(p == NULL)
	{
		return ;
	}
	else{
		for(i = 0; i < n; i++)
		{
			if(p[i] != NULL)
			{
				free(p[i]);
				p[i] = NULL;
			}
		}
	}	
}
int main(int argc, char *argv[])
{
	char **a = NULL;
	int n = 3;
	int i;
	if(getMem(&a,n) != 0)
	{	
		return -1;
	}
	print(a,n);
	
	printf("  after sort_point():\n");
	sort_point(a,n);
	print(a,n);
	
	printf("  after sort_mem():\n");
	sort_mem(a,n);
	print(a,n);
	
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值