C语言知识点<重要>

代码对齐:全选,Alt+F8
break用于switch,用来终止switch语句
break用于for循环则用来终止for循环
break不能用于if语句,除非if语句在for循环内部
在循环嵌套,多层循环中,break只能终止距离它最近的循环,或终止距其最近switch语句
数组:占用内存中一片连续的存储空间,每个元素相当于一个变量,所有元素存储相同的数据类型,数组名代表该存储空间的首地址的地址值
数组变量的批量定义,存储大量同类型数据,模拟现实世界
最原始的数组很少用,因为对数组进行查找、排序、倒置等需要自己编写程序,常用的是以数组为内核的工具
使用数组先进行初始化,否则内部为垃圾值
函数的使用,避免了重复的工作,有利于程序模块化设计
能够完成特定功能的代码段
函数值类型,即函数返回值类型,函数名前定义类型和return语句返回数据类型不一致,则以函数名前定义为准
return为空,即return;语句的作用是终止整个函数,不向主调函数返回任何值
**********


//  函数


void func(void)
{
return;
}
//作用是终止函数,不向主调函数返回任何值


int func(void)
{
return 10;
}
/*
 作用一、是终止函数;二、向主调函数返回10
break用来终止循环或者switch语句,return用来终止函数
函数值类型,即函数返回值类型,函数名前定义类型和return语句返回数据类型不一致,则以函数名前定义为准
return为空,即  return;  语句的作用是终止整个函数,不向主调函数返回任何值
*/


****************
主函数可以调用其他函数,反之不成立,
函数,主函数普通函数,有参函数无参函数,库函数用户自定义函数,有无返回值函数
主函数是程序入口,也是函数出口

对库函数的声明是通过#include<file.h>  .h文件里面是函数原型
函数调用出现在函数定义前面,则要对函数进行声明,函数原型法
形参和实参,个数相同,一一对应,数据类型相互兼容
函数是C语言的单位,类是C++,C#,JAVA的单位
函数内部变量重复定义,特别是形参中有,然后在函数内部又定义了一次
函数的形参也属于局部变量
全局变量的作用范围是从定义的位置到整个程序结束,注意当一个函数放在所谓的全局
变量之前,则该函数不能调用该全局变量
在函数内部定义的全局变量名和局部变量名字一样时,局部变量会将全局变量屏蔽
int* p;表示变量是一个指针,指针本身就是一种变量,存储的是该指针指向变量的地址
int*  是一种用法,*p  是一种用法,地址是内存单元的编号
指针变量是存储地址的变量,指针变量和指针不一样,指针变量是变量只是存储的内容是地址或指针变量存储指针,指针是地址,指针本质是操作受限的非负整数


指针表示一些复杂的数据结构,快速的传递数据,使函数返回一个以上的值,能直接访问硬件,能方便的处理字符串,是理解面向对象的语言中引用的基础


地址:是内存单元的编号,从零开始的非负整数   范围{ 0 ----- 4G-1 }
***********************************************
常犯错误之一
#include<stdio.h>
int main()
{
int * p;   /*因为指针变量未进行初始化,p里面是一个垃圾值,可以读出来
但是无法读取 *p 里面的内容,该垃圾地址值也是对应内存中一个单元,垃圾值(地址值)对应的单元内容可能系统为分配,没有权限进行操作,即不能将的i值赋值给指针p所对应的存储单元,*p = i;  */
int i;
i = 5;
*p = i;
printf("%d",*p); //
}
/*
程序分配了两块儿空间,一个是i一块是*p
程序用变量i的值去修改一个空间
*/
/*运行会出现错误,自我感觉是指针p未指向变量i*/
***********************************************************
int * p;  //p是指针变量,未进行初始化,里面是垃圾值,但是可以将该垃圾值(地址)读出来,但是无法读取 *p 里面的内容
*的三种用法 1、乘法   2、int * p;定义了指针变量p,p只能存放地址   
3、指针运算符 放在已定义好的指针前面,*p还是变量,是以p的内容为地址的变量
*********************************************
#include<stdio.h>
int main()
{
int * p;
int * q;
int i = 5;
      p = &i;
*q = *p;   //  error
printf("%d",*q); 
}
/*也会有错误原因同上,因为q也是指针,未进行初始化,里面是垃圾值(地址值)可以读出来
但是无法读取 *q 里面的内容,不能将指针P所指向的内存单元里面的值赋予垃圾值对应的内存单元
同样 *q = p; 更是错误,因为*q 是int型,而p是int * 型,也是错误
若想不出错,让指针q指向指针p所指向的内存单元,或将变量i的地址赋予指针q*/
q的空间属于本程序,则本程序可以读取*q的内容,
若q的内部是垃圾值,本程序不能读取*q的内容,
*q所代表的内存单元控制权限并没有分配给本程序,不能对该内存单元进行读写
原因是指针是垃圾值(地址是随机的)
它对应的内存单元可能是其它程序正在用,系统未释放


**********************************************************
在C语言中,可能有多个指针同时指向同一个内存单元,如果只使用不释放内存会越来越少,需要用函数进行释放,但只能释放一次,,多释放会报错**********************************************************
#include<stdio.h>
void exchange(int, int);  //函数声明
int main(void)
{
int a, b;
a = 3;
b = 5;
exchange(a,b);
printf("a = %d ,b = %d \n", a, b);  //输出a b值未改变
return 0;
}


void exchange(int a, int b)   //函数
{
int t; //注意 形参中定义了变量a b 在函数中便不能重复定义,形参也是局部变量
t = a;
a = b;
b = t;

}
/*
不能实现a b互换
主函数中a b和自定义函数中的a b是互不相同的四个变量,
在exchange函数内部无法对主函数中的a b进行处理,因为没有接入主函数中变量a b的地址,若相对主函数中变量a b进行处理要接入其地址
或者在主函数中对a b进行了互换,但作用仅在自定义函数内部,调用完函数,自定义函数中a b就释放了,输出还是主函数中变量a b 
*/
+***********************************
#include<stdio.h>
void exchange(int *, int *);  //函数声明
int main(void)
{
int a, b;
a = 3;
b = 5;
exchange(&a,&b);
printf("a = %d ,b = %d \n", a, b);  //输出a b值未改变
return 0;
}


void exchange(int * p, int * q)   //函数
{
int * t; //注意 形参中定义了变量a b 在函数中便不能重复定义,形参也是局部变量
t = p;
p = q;
q = t;
}
/*
不能实现a b互换
因为虽然指针p q接入了变量a b的地址,但自定义函数内部交换的是p q的值,
p本来存放的是a的地址,q存放的是b的地址,互换之后,
p存放的是b的地址,q存放的是a的地址,交换的不是*p *q的值
对主函数a b值没有影响
*/
**********************************************
#include<stdio.h>
void exchange(int *, int *);  //函数声明
int main(void)
{
int a, b;
a = 3;
b = 5;
exchange(&a,&b);
printf("a = %d ,b = %d \n", a, b);  //输出a b值未改变
return 0;
}


void exchange(int * p, int * q)   //函数
{
int t; //注意 形参中定义了变量a b 在函数中便不能重复定义,形参也是局部变量
t = *p;
*p = *q;
*q = t;
}
/*
能实现a b互换
因为自定义函数不但实现了指针p q接入了变量a b的地址,同时交换了变量a b的值
*/
*********************************************
#include<stdio.h>
void f(int i);
int main(void)
{
int i = 6;
printf("i = %d\n",i);
return 0;
}
void f(int i)
{
    i=99;
}
/*即便形参与实参名字是相同的,但是形参与实参是不同的变量
函数内部定义的变量与形参都是局部变量,且形参也属于变量
函数中定义的变量名与形参不能相同,形参是变量用来接收实参数据的变量


函数就是一个工具,要用到就调用相关函数就可以了,
一旦函数调用完比,函数内定义的变量的空间就会被释放,这就解释了实参与形参中同名变量是不同的变量
****************************************************
如何通过被调函数实现修改主调函数普通变量的值,
1、实参必须是该普通变量的地址
2、形参必须是指针变量
3、在被调函数中通过 *指针变量 = ...的形式,就可以修改主调函数相关变量的值
4、指针可以使函数返回一个以上的值
****************************************************
数组名是该数组所占内存空间首地址的地址值,即,第一个元素地址的地址值,
是一个地址常量
对字符串进行处理只需要字符串的首地址就行了,因为字符串有特殊的结束标志,但对于数组处理不仅需要首地址还需要数组的长度,因为数组没有特殊结束标志
p是数组名,则p[i]就是*(p+i)
a[5]; 可知  a[3]=*(a+3) 数组名a是地址常量
***********************************************************
数组中元素的输出:提现了指针的优势,
#include<stdio.h>


void arr(int * p, int len);   //函数声明


int main()
{
int n, i;
int a[100];
printf("please input the length of a array: ");
scanf("%d",&n);
printf("please input the a array\n");
for(i=0;i<n;i++)
scanf("%d",&a[i]);
arr(a,n);   //函数调用
return 0;
}


void arr(int * p, int len)   //函数定义
{
int i;
for(i = 0;i < len; i++)
printf("%d  ",*(p+i));//可以换成printf("%d ",p[i]);
}
**********************************************
调用函数对主调函数中变量值进行修改的办法
#include<stdio.h>
void f(int i);    //函数声明
int main()
{
int k=5;
printf("%d", f());   //值得输出,同时调用了函数
return 0;
}
void f(int i)  //函数定义
 {
.....
 }
/*若自定义函数不通过返回值则永远无法对主函数中变量k的值进行修改
除非用指针,传变量k的地址,因为变量k与变量i不是同一变量*/
********************************************************
指针不能相加、相除、相乘,两个指针指向同一块儿连续存储空间的不同存储单元,这两个指针可以相减
sizeof(类型标识符)
地址就是指针,指针就是地址,是内存中存储单元的编号,硬件中是一个字节一个地址
指针变量在内存中占用4个字节,指针变量的地址是所占字节中第一个字节的地址
double x = 66.66;
double * p = &x;
双精度变量x本身占8个字节,x变量的地址是8个字节中第一个字节的地址,指针变量p指向x,p中存放的是8个字节中,第一个字节的地址,又说p指向双精度变量x
一个变量无论占多少个字节(一个字节一个地址),它的地址是首字节的地址
*****************************************************
传统数组的缺陷:
传统数组长度是固定的,只能是常量,不能是变量
数组一旦定义系统为其分配的空间程就一直存在,序员无法手动编程释放,只能是其所在的函数运行完由系统释放;在一个函数运行期间,系统为数组分配的空间就会一直存在,直到函数运行结束,系统才会释放
数组的长度不能在函数运行过程中动态扩充或缩小
传统方式定义的数组无法跨函数使用
*****************************************************
malloc函数(memory allocate)内存动态分配
#include<stdio.h>
#include<malloc.h>
int main()
{
int i = 5; //定义静态变量,系统分配了4个字节
int * p = (int *)malloc(4);  //该句分配了8个字节
return 0;
}
/* 4表示请求系统分配4个字节,malloc函数形参只有一个,且是整型,包含于malloc.h文件中,
返回是第一个字节的地址,前面加强制类型转换,表明指向变量的类型占用多少个字节,
int * p = (int *)malloc(4);  //该句分配了8个字节,指针p占4个字节,p指向的空间占4个字节
指针变量p所占内存是静态分配的,p所指向的空间是动态分配的
变量i所占空间是静态分配的,*p相当于一个整型变量,所占空间间是动态分配的
free(p);表示将p所指向的空间释放掉,指针变量p本身所占的字节不会被释放,只能在p所在函数终止时有系统释放*/
*****************************************************
#include<stdio.h>
#include<malloc.h>
void f(int * q);  //函数声明
int main()
{
int * p = (int *)malloc(sizeof(int));
*p = 10;
printf("*p = %d\n",*p);
f(p);         //函数调用
printf("*p = %d\n",*p);
return 0;
}
void f(int * q)    //函数定义
{
*q = 200;
free(q);
}
/*指针变量p是静态分配,本身占用4个字节,指针p所指向的空间是动态分配的,占4个字节,
该动态分配的空间相当于*p,一个整型变量,p存放了该空间(malloc函数分配空间)的地址
通过自定义函数修改指针变量p指向的malloc函数所分配的空间的值,在一个函数由malloc函数分配的空间,在另一个函数中进行修改
p作为的实参传递给函数的形参q,那么q也指向malloc函数所分配的空间
若在自定义函数中将q所指向的空间释放掉,第二次输出*p就会出错,释放掉了就不能将空间存储的值进行输出*/
*****************************************************
动态内存分配实例
#include<stdio.h>
#include<malloc.h>
int main()
{
int i,n;
printf("Please input: ");
scanf("%d",&n);
int * p1 = (int *)malloc(n*sizeof(int));//55行
double * p2 = (double *)malloc(n*sizeof(double));//66行
for (i=0;i<n;i++)
scanf("%d",&p1[i]);
printf("一维数组内容是:");
for(i=0;i<n;i++)
printf("%d  ",p1[i]);
return 0;
}
/* 55行相当于 int p1[n]; 动态的构造了一个一维数组,66行相当于double p2[n]; 动态的构造了一个一维数组
由于malloc函数分配的空间首地址赋予指针变量p1,即p1指向malloc函数分配的空间,int p1[n]两者等价,才能用p1[i]
指针变量pArr指向前4个字节,则pArr+1指向第二个4个字节*/
*****************************************************
静态内存是由系统自动分配的,由系统自动释放,静态内存是在栈分配的
动态内存是程序员手动分配的,手动释放,是在堆分配的
多级指针,指向指针变量的指针,存放的是指针变量的地址
静态内存不可以跨函数使用,因为函数执行完毕,其所占空间就会被释放(出栈)(所占空间是由系统分配的,执行完就会被释放,导致一个指针变量指向一个空间出现错误),而动态内存可以跨函数使用,是由malloc函数动态分配的,即可以在另一个函数中对一个函数中变量的值进行修改,可以使主调函数中一个指针变量合法指向一块儿存储空间,在一个函数造出一块空间,在另一个函数在使用(动态分配)
通过被调函数对主调函数中变量的值进行修改,实参应该是普通变量的地址,形参应该是指针变量
动态内存可以跨函数使用:
#include<stdio.h>
#include<malloc.h>
void f(int ** q);    //函数声明
int main()
{
int i=5;  //静态分配
int * p = &i;
printf("%d\n",*p);
f(&p);           //函数的调用
printf("%d\n",*p);
return 0;
}
void f(int ** q)     //函数定义
{
*q = (int *)malloc(sizeof(int)); //动态内存分配,当f函数执行完毕,该快空间未被释放
                                //若是静态分配,f函数执行完毕,空间会被释放
                                     //等价于 p = (int *)malloc(sizeof(int));
**q = 100;  //指针变量q指向变量p存放的是指针变量的地址          
}
//指针变量p合法指向f函数中的一块存储单元(该存储单元也没有被free函数释放)
*****************************************************
数据66.6在C语言中默认是double类型,如表示是float类型则写成66.6F或66.6f
结构体相关:
#include<stdio.h>
struct student
{
int age;
float score;
char sex;
};   //定义了一种数据类型,和int、float、char地位上相同
int main()
{
return 0;
}
/*定义自己的变量--结构体
为了用户根据实际需要,将基本数据类型组合在一起,而定义的一种新的数据类型,
表达复杂的事物,而基本数据类型有无法满足需要时
定义结构体变量时可以整体进行初始化,而定义完之后只能单个进行赋值
    结构体变量名.成员名
    (*结构体指针).成员名  //  注意加括号
    结构体指针->成员名    //在计算机内部会被转化为 (*结构体指针).成员名,两者等价
    定义结构体类型后要加分号;
    仅仅声明了结构体类型,相当于 int float 等;并未给其分配内存空间;
    定义了变量系统才会根据变量类型为其分配一定字节的内存空间,因此定义了结构体
    变量系统会根据成员情况为其分配一定字节的内存空间,但是只使用结构体指针,
    不定义结构体变量要用malloc()函数开辟内存空间
    因此得到一点定义了变量系统会为其分配内存空间,只使用指针,需要用相关函数
    开辟内存空间


  声明了一个结构体变量相当于声明了若干个结构体成员;
/*struct stu *p;   //定义结构体指针,结构体指针->结构体变量
p=&boy2;         //结构体指针初始化
boy2.name   (*p).name  p->name   //三者等价
pst->age含义是结构体指针指向结构体变量中的age成员*
*****************************************************
对结构体变量输入必须发送地址 对结构体变量的输出可以发送地址也可以发送内容
/*通过调用函数来对结构体进行输入输出*/
#include<stdio.h>
#include<string.h>
void inputstudent(struct student *stu); //函数声明
void outputstudent(struct student *stu);//声明错误导致调试不出
struct student
{
char name[50];
int age;
float score;
char sex;
float hight;
float weight;
};     //  定义结构体这种数据类型,这种数据类型名称是 struct student,注意分号


int main(void)

    struct student st1;  //定义结构体变量
struct student * pst = &st1;    //定义结构体指针变量,并进行初始化,指向结构体变量
inputstudent(&st1);
outputstudent(&st1);
return 0;
}
void inputstudent(struct student *stu)
{
strcpy(stu->name,"张三");
stu->age = 18;
stu->score = 100;
stu->sex = 'M';
stu->hight = 175;
stu->weight = 60;
}
void outputstudent(struct student * stu)
{
printf("name : %s\nage : %d\nscore : %f\nsex : %c\nhight : %f cm\nweight : %f kg\n\n\n\n"\
,stu->name,stu->age,stu->score,stu->sex,stu->hight,stu->weight);
}
/*输出是发送地址,优点是执行速度快,占用内存少
如果发送的是变量,编译系统会开辟两份内存*/
*********************************************************
结构体变量可以相互赋值
**************************************
文件操作
#include<stdio.h>
int main()
{
FILE * file = NULL; 
int character;
file= fopen("text.txt","r");
if (file != NULL)    
{
do
{
character = fgetc(file);
printf("%c",character);
} while(fgetc(file) != EOF);
printf("\n\n\n");
}
fclose(file);
return 0;
}
/*fgetc()函数一次读取一个字符,用循环将文件中的字符读出*/
经典代码
#include<stdio.h>
#define MAX_NUM 1000
int main()
{
char string[MAX_NUM] = "";  //定义字符型数组,顶初始化为空字符,自我理解输出字符串的临时中转站,用来存数读取的字符串
FILE *file = NULL;      //定义"文件类型"指针
file = fopen("text.txt","r"); // 以只读方式打开文件
if (file != NULL)        //检测文件是否打开成功
{
while (fgets(string,MAX_NUM,file) != NULL)//函数返回值类型是指针,若指针不为空则继续循环
   printf("%s",string);  //字符串输出
fclose(file);   //关闭文件
}
else
printf("文件打开失败\n\n");
return 0;
}
****************************************************************
FILE* fopen(const char* fileName, const char* openMode);函数fopen的原型
int fgetc(FILE * pointeronfile); fgetc函数原型
char* fgets(char* string, int characterNumberToRead, FILE* pointerOnFile); fgets函数原型 
fputc:在文件中写入一个字符(一次只写一个)
int fputc(int character, FILE* pointerOnFile);
fputs:在文件中写入一个字符串
函数和fputc类似,区别是fputc每次是写入一个字符,而fputs每次写入一个字符串。
int fputs(const char* string, FILE* pointerOnFile);
类似地,这个函数也接受两个参数:
string:要写入的字符串。
pointerOnFile:指向文件的指针。
fprintf:在文件中写入一个格式化过的字符串,用法与printf是几乎相同的,只是多了一个文件指针
int rename(const char* oldName, const char* newName);
oldName就是文件的“旧名字”,而newName是文件的“新名字”
#include<stdio.h>
int main(int argc, char *argv[])
{
rename("text.txt","hello.txt");
    return 0;
}
int remove(const char* fileToRemove);
#include<stdio.h>
int main(int argc, char *argv[])
{
remove("hello.txt");
    return 0;
}
fileToRemove就是要删除的文件名
注意:remove函数要慎用,因为它不会提示你是否确认删除文件。文件是直接从硬盘被永久删除了,也不会先移动至垃圾箱
int fseek(FILE* pointerOnFile, long move, int origin);
此函数能使游标在文件(pointerOnFile指针所指)中从位置(origin所指)开始移动一定距离(move所指)。
move参数:可以是一个正整数,表明向前移动;0(不移动);或者负整数,表明回退。
origin参数:它的取值可以是以下三个值(define所定义的常量)中的任意:
SEEK_SET :文件开始处
SEEK_CUR :游标当前所在位置
SEEK_END :文件末尾
来看几个具体使用实例吧:
fseek(file, 5, SEEK_SET);
这行代码将游标放置到距离文件开始处5个位置的地方。
fseek(file, -3, SEEK_CUR);
这行代码将游标放置到距离当前位置往后3个位置的地方
fseek(file, 0, SEEK_END);
这行代码将游标放置到文件末尾。
void rewind(FILE* pointerOnFile);
这个函数的作用就相当于使用fseek来使游标回到0的位置































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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值