C基础复习

Posted Lammy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C基础复习相关的知识,希望对你有一定的参考价值。

  因为学习视频解码。不得不重新复习下C语言呢,3年都没碰了嘿嘿!

1、c与java不同它没有boolean和byte这2个基本类型,boolean在c中利用0和非0来代替,0为false,非0为true。byte为一个字节,在c中可以用char类型来代替。

C中各种基本类型所占的字节数:(利用sizeof得到的)

    char 占1个字节 (java中2个字节

    short 短整型 2个字节

    int  4个字节

    long 占4个字节

    double占8个字节

2、 c语言的输出占位符:

    %d  - int

    %ld  - long

    %c   - char

    %f  - float

    %hd - short

    %lf    - double

    %x  - 16进制输出int或long、short

    %o - 八进制输出

    s%  - 字符串输出

3 指针也是一种数据类型,指针是指向对象的在内存中的地址:&i代表的是i的地址(给指针赋值时用到)

如:p的值就是i在内存中的地址,*p则是地址中的值,可以用数组的指针变量来访问数组:如下面程序运行: 

	int i = 10;
	int *p = &i;
	char a[3] = { \'a\', \'b\', \'c\' };
	printf("i:%d \\n", i);
	printf("p:%d\\n" , p);
	printf("*p:%d \\n", *p); 
	printf("&i:%d \\n", &i);
	printf("*(p+1):%d \\n", *(p+1));
	printf("*a:%c \\n", *a);
	printf("*(a+1):%c \\n", *(a + 1));

  

 输出的结果为:

  

 4 指针的指针,即多级指针。

就是指针是个变量,它也有地址,指向指针变量的地址即为地址的地址,即二级指针变量。如下:

     int i = 10;
	int *p = &i;
	int **c = &p;
	
	printf("%d\\n",c);	//c指针变量是地址的地址
	printf("%d\\n", *c);	// *c为c指针变量地址里的值
	printf("%d\\n", **c);//	*cc 是以c指针变量指向的地址的值为地址的值

  5 通过指针来修改变量值:

    int i = 10;
    int *p = &i;
    int **c = &p;
    **c = 4;
    printf("%d\\n",i);    //c指针变量是地址的地址
View Code

执行后i的值为4

  6 字符串指针数组的定义

数组指针,和遍历字符串指针(同理可以用到其他类型的数组指针上)。如果数组指针和指针数组不清楚看下一条。

(1)、字符串是由字符指针或者字符数组实现的,其实都可以看作是字符指针,结束符为\\0

(2)、数组相当于一个指针,字符串指针数组相当于是个2级指针数组,数组内元素指向指针的指针。如下面代码中*str[],通过调试验证它的结构是下面的:

 

假设有char *x = “abc” ,char *y = “def”  char *z = “ghi”  而*str[] 由x y z对应的字符串数组组成。x、y、z指针变量对应的是第1、2、3个字符串的地址.下面我们str指针变量则是指向这三个字符串指针变量的指针,即如下:

 

            x------> abc的地址

            y-------> def的地址

            z------> ghi的地址

下面我们要用str来指向的是:x、y、z三个字符串地址的变量的地址,因此str也是一个字符数组指针来指向x、y、z三个变量的地址的。即

          str={x的地址,y的地址,z的地址}

因此char **p = str; 

*p 则是a的地址,**p对应的是a的值

*(p+1)对应的是d的地址, **(p+1)是d。 

	//字符串是由字符指针或者字符数组实现的,其实都是字符指针,结束符为\\0
	char *b = "dadaf";
	char ab[] = { \'a\', \'d\' };

	//一般指针赋予的是地址
	char a[] = "abc";
	char *str[] = { "abc", "def", "ghi" };
	char **p = str;

	int i, j;
	for (i = 0; *((*p)+i)!= \'\\0\'; i++)
	{
		for (j = 0;(*(p+i))[j]!=\'\\0\'; j++)
		{
			printf("%c\\n", *(*(p + i) + j));
		}
	}

  7、 区分数组指针指针数组

判断一个指针变量是什么主要是看它和什么在一起,和*在一起就是指针,和[]在一起就是数组,和()在一起则就是函数。再看它然后和什么在一起,再继续判断。如上面的*str[],str是和[]在一起的,因此首先判断str是个数组,然后和*在一起,指针也是数据类型,因此是指针类型的数组,即数组中存储的是指针变量。

如:

  1、*str[] 和*(str[])是一样的,是指针数组 (根据符号优先级来看,[]的优先级高于* ,符号优先级可以看下博客:http://www.cnblogs.com/bokeofzp/p/4748283.html);

      2、(*str)[]  才是数组指针,初始化如下:

    char a={\'a\',\'b\',\'c\'};

    (*str)[] =&a;

 c语言是类型安全的语言,类型不一样即使值一样也是不能进行赋值的,这点不同java。&a是指向整个数组,而a指向的是数组的第一个元素。把他们赋值给变量,存储的地址值是相等的,但是它们的类型不一样也不能相互赋值。

 

  8 结构体与结构体指针。

1、结构体里面定义各种类型的变量,但是不能定义函数,但是可以有函数的指针变量。

2、结构体指针可以直接在{}后加上*p,加上变量p则表示结构体变量。

3、c语言中所有变量只有初始化了后才可以使用。结构体指针变量只有初始化了,即分配了内存地址后才可以使用,当然也可以指向现有的结构体。

4、结构体想利用原有的默认值就不要自己申请空间,直接定义结构体变量,想用结构体指针可以定义指针变量指向定义好的结构体。如下:注意里面的代码注释

5 结构体指针如 p->age 等同与 (*p).age,具体看代码解释。

#include "stdafx.h"
#include <stdlib.h>
#include <malloc.h>

int add(int a, int b);
int add(int a,int b)
{
	return a + b;
}
struct person
{
	int age=2;
	char sex;
	int(*pf)(int, int) = add;//
	
};


int _tmain(int argc, _TCHAR* argv[])
{
	//不用结构体指针就类似与java里的类,默认的成员变量的值都可以用。
	person p;
	int age = p.age;
	int addResult = p.pf(2, 3);
	printf("%d\\n", age);

	/*
	需要先对person类型的指针a分配内存,分配的内存是按结构体的类型分配的,但是分配的内存里是没有成员变量的值的因此需要用到里面的成员变量
	就必须先初始化,或者用上面的定义一个person 类型的结构体,再用a指向它,不过这样就多此一举了。
	*/
	person *a = (person * )malloc(sizeof(person));
	//C语言中由对结构体指针用的比较多,每次(*a).age比较麻烦,就设计了符号方法->,代表结构体指针指向的对象,例如下:
   (*a).age =23;
	a->age = 23;
	//因为a是重新申请的地址,因此用add必须重新初始化
	a->pf =add;
    int addResult = (a->pf)(2, 3);
	 printf("%d\\n", addResult);	

	return 0;
}

  

     9 、函数

1、C里的函数一般是先声明,然后定义的。

2、c中函数与java和c++不同,是不可以重载的。

3、C中结构体内不可有函数的定义,但可以又函数的指针变量,相当于结构体的成员函数。可以参考第八条的代码和注释

4 、函数的名称就是指向该函数地址的指针

5、形参和实参,

  (1)形参只有在函数被调用时候才会占用内存,并且将实参传递给形参,值传递是单向的,不能由形参传递给实参。

  (2)如果形参是指针,传递的是地址变量,则通过指针在函数里就会改变实参的值。

  (3)形参只在函数调用时候占用内存,函数调用完毕就会被释放掉。

  10、联合

联合的定义和结构体相同,联合表示几个变量是用一个内存,当联合被说明时,编译程序会自动产生一个变量,长度为所有变量类型中长度最大的值,改变一个变量的值另外的变量的值也会改变。

#include "stdafx.h"
#include <stdlib.h>
#include <malloc.h>

int add(int a, int b);
int add(int a,int b)
{
	return a + b;
}
union un
{
	int a;
	char sex;
};

int _tmain(int argc, _TCHAR* argv[])
{

	 un mm;
	 mm.a = 95;
	 mm.sex = \'m\';

	 printf("a = %d \\n sex = %c" , mm.a , mm.sex);
	

	return 0;
}

  打印:a = 109

     sex = m

109的是将m转化为assic码的值。

  11、 枚举

枚举是一串不变的常量,默认情况下是从0开始一次加1的整数,也可以是对应的assic码值。若中间有定义值后面的值就加一:

#include "stdafx.h"
#include <stdlib.h>
#include <malloc.h>

enum number
{
	x1, x2, x3=97 , x4
};
int _tmain(int argc, _TCHAR* argv[])
{

	int i = 0;
	number x = x1;
	number y = x4;
	printf("%d , %c",x ,y);

	return 0;
}

  打印的结果为:0  b

  12 类型说明 typedef

类型说明是将已定义的变量或者结构体、联合、枚举定义为另一种新的名字,如下面int i 与java_int i是等同的。

typedef int java_int;
int i;
java_int i;

  其实这常用于结构体中:定义这种结构体为student,当然也可以如第8条那样定义结构体。

typedef  struct
{
char *name;
int age;
char *email;
}sudent;

student a;;

  13、预处理指令

预处理指令一般放在文件的前面。

    (1)#define:是一个宏定义指令

        <1>#define +宏替换名字(字符串或者数值)如:#define TRUE 1 就是编译器遇到TRUE这个字符串时候就当1处理。

        <2>#define + 函数  如:#define MAX(x , y) x>y?x:y   ------这里和枚举一样没有数据类型,当传入整型、字符时候就可以判断大小,但是如字符串等不能比较大小的就会报错

    (2)#error 是调试用的,比如当你预计程序会发生什么意外时候就可以用#error来处理。当程序遇到#error时候编译就会停止。

    (3) #inlude 引入源文件的指令

    (4)  #if ...#else...#endif

    (5) #unde 删除原来定义的宏定义#define TRUE 1 后可以用 #unde TRUE 让宏定义用在所指定的文件里。

    (6) #ifdef 和ifndef 如果定义了,如果没定义。

   

 14 动态分配内存,以及字符串数组与字符串指针使用注意的地方

   1、malloc 是返回void *类型的函数,用于动态分配内存。原型extern void *malloc(unsigned int num_bytes);分配整数个byte。它是申请umb_bytes个内存空间,并返回指针变量指向申请的空间的头。

   2、sizeof计算数据类型的大小的。例如分配100个字符的字符串指针。 char *a =(char*) mallic(100*sizeof(char));需要将void*强制转换为char*。

   3、sizeof(a)如果a是字符串指针类型的话返回的就是4,表示的是字符串指针变量a的内存大小,如果a是数组的话返回的就是整个数组的内存大小。参见下面2条,char a[] ="abc";这是字符串指针来定义的,a其实是指针不是数组。

   4、字符数组和字符指针的区别,除了上一条的区别外,char a[10]其实占用10个字节。而我们指针定义一个字符 char * a ="abc"时其实占用的4个空间,后面有字符串结束符 \\0。

    这里需要注意的是char a[] = "abc",其实是用指针在定义,返回的是字符串指针a。char ca[] = { \'a\', \'b\', \'c\' },这才是数组的定义,它是固定大小的因此不需要字符串结束符。可以用sizeof(a)查看,前面是4,后面的数组定义返回的是3。主            要如果是char *a ="abc"这样定义的话,用sizeof(a)得到的指针变量a的值,它是abc字符串的首地址的变量占四个字节,因此无论申请的多大的内存返回的都是4.

   5、当我没定义一个字符串指针的时候char *a,需要为a分配地址为字符串分配内存时就要用malloc分配内存,一般是固定大小的,我们一般要多申请一个字符空间来存储\\0 ,且存在最后。否则即使我们只申请了10个字符空间。用printf(“%s” , a );            时候就会打印很多个字符直到后面的内存里面\\0结束符(\\0 是ox0000 0000),这样就容易导致错误。因此如果要存储100个字符我们可以这样:char *a; a= (char *)malloc(101) ; *(a +100)=\'\\0\' ,然后可以去读文件或者用其他变量赋值,如果不这样再打印的时候就得注意了,根据实际需要来处理吧。

 15 文件的读写

  1、c现在处理文件,打开文件时候为了安全起见已经渐渐用fopen_s代替原来的open了。

  2、原型:errno_t fopen_s( FILE** pFile, const char *filename, const char *mode );如果成功返回0(创建了文件或者打开已有文件),失败则返回相应的错误代码。错误代码请到_doserrno,errno, _sys_errlist, and _sys_nerr去了解更多

 

      pFile:文件指针将接收到打开的文件指针指向的指针。

 

      filename :文件名。

 

      mode :允许的访问类型。
          mode说明:
               "r"              打开以进行读取。如果该文件不存在,或无法找到,fopen_s调用失败。
               "w"      打开一个空文件以进行写入。如果该文件存在,其内容将被销毁。
               "a"      打开以进行写入 (追加) 而不将新数据写入文件之前删除的 EOF 标记文件的末尾。如果它不存在,则创建该文件。
               "r+"        将打开并读取和写入。 (该文件必须存在)。
               "w+"      打开一个空的文件进行读写。如果该文件存在,其内容将被销毁。
               "a+"      将打开并读取文件和追加。追加操作包括删除 EOF 标记的新数据写入到文件并在编写完成后还原 EOF 标记之前。如果它不存在,则创建该文件。
               “b”      打开二进制 (未翻译) 模式 ; 翻译涉及回车和换行字符不会显示。
              当然还有其他的模式具体参考:http://baike.baidu.com/link?url=qt2ToB8EqjyGlBo2eOEpjKSBWyn_uQJ7M8v1nQd9WPJ7ojGahicedOL8bjTK_Uan5ZtzFqVR8L4U5nhEdjT_f_
  3、编码:fopen_s支持 Unicode 的文件流。若要打开新的或现有的 Unicode 文件,请传递ccs标志,它指定所需的编码为fopen_s::fopen_s(&fp, "newfile.txt", "rw,ccs=encoding");允许的值encoding的UNICODE,UTF-8,和UTF-16LE.如果存在未指定值的encoding,fopen_s使用 ANSI 编码。如果该文件已经存在,并且已打开以进行读取或追加,字节顺序标记 (BOM),如果存在于文件中,将确定的编码。物料清单编码优先通过编码由ccs标志。ccs没有物料清单时存在,或如果该文件是新文件只使用编码。
  4、fread、fwrite的用法,以及上面一条所讲的动态分配空间的demo,和自定义的一个小的缓存机制:
    
#include "stdafx.h"
#include "malloc.h"

void write_file(char *name,char text[],int lenth)
{

	FILE *f;
	errno_t  result = fopen_s(&f, name, "w");
	fwrite(text, 1, lenth, f);
	fclose(f);
}
int main()
{

	//FILE *f;
	char text[] = "my name is zpfafafafhahhahahahffffffffffffffffffffffffllllllllllllllllllllllllllllllaaaaaaaaaadadddddddddddddddddddddddda!";//写入文件里的内容
	int lenth = sizeof(text) / sizeof(text[0]);//减去结束符
	char *name = "myname";
	write_file(name, text, lenth);

	char * text2;
	text2= (char*)malloc(200);//* sizeof(char)
	
	
	FILE *f;
	fopen_s(&f, name, "r");;
	//自定义的一个小的缓存机制,每次读取10个字节
	int readResult = 1; 
	int current_char = 0;
	char * data ;
	data = (char *)malloc(10);
	while (readResult != 0)
	{
		readResult = fread(data, 1, 10, f);
		if (readResult == 0)
			break;
		else
		{
			int i;
			for (i = 0; i < readResult; i++)
			{
				*(text2 + current_char) = *(data + i);
				current_char++;
			}
		}

	}
	printf("%s\\n", text2);

	fclose(f);
	return 0;
	
}

  

 

以上是关于C基础复习的主要内容,如果未能解决你的问题,请参考以下文章

每日道代码题001- PYTHON基础复习

[Go] 通过 17 个简短代码片段,切底弄懂 channel 基础

js基础复习---字符串操作

C基础复习

JSP 基础语法

C语言 基础语法汇总 期末复习