内容简介:每个标准库函数都会被声明在一个或多个标准头(standard header)中。每个标准头都包含一组相关的函数声明、宏和类型定义。例如,数学函数声明在头文件 math.h 中。标准头也称之为头文件(header file)
每个标准库函数都会被声明在一个或多个标准头(standard header)中。
每个标准头都包含一组相关的函数声明、宏和类型定义。例如,数学函数声明在头文件 math.h 中。标准头也称之为头文件(header file)
C 程序只会在两种运行环境中执行:宿主(hosted)环境或独立(freestanding)环境
vs上是宿主的,独立的我猜是写入硬件吧,估计使用的库也少。
发现C中的printf打印字符串,对类型必须 必须正确 ,不存在C#的隐式转换。比如输出的一个数字,不用ToString(),C中的字符串是%s,数字%d 浮点%f
标准库的函数不一定确保可重入(reentrant)。也就是说,在一个进程中两次调用同一个函数并行执行可能是不安全的行为。之所以制定该规则,其中一个原因是:部分标准函数会使用和修改同一个静态变量或线程变量。
因此,你不能在信号处理进程(signal handling rountine)中调用标准库函数。信号是异步的,也就是说,程序可能在任何时候收到信号,甚至是正在执行标准库函数时。当发生这种情况时,如果信号处理器再调用的标准函数与正在执行的是同一个,那么该函数则必须是可重入的。
线程安全(thread-safe):可以“同时”被几个线程安全地执行
如果头文件的定义的函数名 与内置的一些函数重名,可以
#undef 取消
把名称放在括号内,也可以调用函数而非宏:
#include <ctype.h> /* ... */ c = (toupper)(c) // 调用函数toupper()
你可以忽略包含宏定义的头文件,直接在源代码文件中明确声明该函数:
extern int toupper(int); /* ... */ c = toupper(c) // 调用函数toupper()
我在C#中经常_XXX,下划线开头代表临时变量,c中不能。
不能_a_形式标识符作为函数名或全局变量名,但是可以作为参数。局部变量和标签名称。结构成员和联合成员也可以使用下划线开头的名称作为标识符,但是第二个字符不可以是下划线或者大写字母.
在所包含的头文件中定义的所有宏标识符,都是被保留的。
(文件名也有影响)在标准头文件中被声明为文件的标识符,在它们自身命名空间范围内,是被保留的。一旦在源文件中包含一个头文件,在同一个命名空间中,不能将在该头文件中声明为文件的标识符用作其他目的,或作为宏名称。
====================www.ayjs.net 杨洋 wpfui.com ayui ay aaronyang=======请不要转载谢谢了。=========
printf输出
从输出结果可以看出:如果是小写的x,输出的字母就是小写的;如果是大写的X,输出的字母就是大写的;如果加一个#,就以标准的十六进制形式输出
特殊符号,用双符号 就可以转义 输出。
输入个值
int i; scanf("%d", &i); //&i 表示变量 i 的地址,&是取地址符 printf("i = %d\n", i);
类似C#的Console.Read();
类似 java 的
Scanner in = new Scanner(System.in);
int a = in.nextInt();
综上所述,scanf 语句的意思就是:从键盘上输入字符 123,然后%d将这三个字符转化成十进制数 123,最后通过“取地址 i”找到变量 i 的地址,再将数字 123 放到以变量 i 的地址为地址的变量中,即变量 i 中,所以最终的输出结果就是i=123。
scanf第一个参数不要加 非输出控制符,比如\n
输入2个值
int i, j; printf("请输入两个值,中间以空格分隔:"); scanf("%d%d", &i, &j); printf("i = %d, j = %d\n", i, j);
运算符,除了C#的,(其实C#也有这个)
有个* 取值运算符 *指针变量
&取地址运算符 &变量名
语言类型:
基本类型
标准整数类型,以及扩充的整数类型
实数浮点类型,以及复数浮点类型
枚举类型
void类型
派生类型
指针类型
数组类型
结构类型
联合类型
函数类型
基本类型和枚举类型,统称算术类型(arithmetic type)。算术类型和指针类型,统称为标量类型(scalar type)。数组类型和结构类型被统称为聚合类型(aggregate type)。联合类型(union type)不被认为是聚合类型,因为在任一时刻下,联合中只有一个成员可以具有值
由外部定义的数组变量就是一个不完整类型:extern float fArr[]; // 外部声明
标准库的头文件针对特定用途定义了很多整数类型,例如用来显示宽字符的 wchar_t 类型。这些类型是 typedef 名称,它们是标准整数类型的同义词。
类型 ptrdiff_t、size_t 和 wchar_t 定义在头文件 stddef.h 中(以及其他头文件中);类型 char16_t 和 char32_t 定义在头文件 uchar.h 中。为了特殊需要,指定位长度的整数类型(带符号和无符号变量)定义在头文件 stdint.h 中。
此外,头文件 stdint.h 也为标准库中的所有整数类型可显示的最大值与最小值定义了宏。例如,SIZE_MAX 等于可以在 size_t 类型变量中存储的最大值。
void讲解:
没有返回值的函数,其类型为 void。例如,标准库函数 perror() 被声明为以下原型:
void perror( const char * );
下面是另一个函数原型的声明,参数列表中的关键字 void 表示该函数没有参数:
FILE *tmpfile( void );
【在C#中直接不写了。。。。】
mpfile("name.tmp"),则编译器会报错
还可以用于类型表达式、
void 类型表达式指的是没有值的表达式。例如,调用一个没有返回值的函数,就是一种 void 类型表达式:
char filename[] = "memo.txt";
if ( fopen( filename, "r") == NULL )
perror( filename ); // void表达式
//void 类型表达式指的是没有值的表达式。例如,调用一个没有返回值的函数,就是一种 void 类型表达式: char filename[] = "memo.txt"; if (fopen(filename, "r") == NULL) perror(filename); // void表达式 //类型转换(cast)运算(void)表达式显式地将表达式的返回值丢弃,例如,如下代码丢弃了函数返回值: (void)printf("I don't need this function's return value!\n");
指向void的指针
一个 void* 类型的指针代表了对象的地址,但没有该对象的类型信息。这种“无数据类型”的指针主要用于声明函数,让函数可使用各种类型的指针参数,或者返回一个“多用途”的指针。例如,标准内存管理函数:
void *malloc( size_t size );
void *realloc( void *ptr, size_t size );
void free( void *ptr );
如下例所示,可将一个 void 指针值赋值给另一个对象指针类型,反之亦可,这都不需要进行显式的类型转换。
#include <stdio.h> #include <time.h> #include <stdlib.h> // 提供以下函数的原型 // void srand( unsigned int seed ); // int rand( void ); // void *malloc( size_t size ); // void free( void *ptr ); // void exit( int status }; enum { ARR_LEN = 100 }; int main () { int i, *pNumbers = malloc(ARR_LEN * sizeof(int)); //获得相同的存储空间 if( pNumbers == NULL ) { fprintf(stderr,"Insufficient memory.\n"); exit(1); } srand( (unsigned)time(NULL ); // 初始化随机数产生器 for ( i=0; i < ARR_LEN; ++i ) pNumbers[i] = rand() % 10000; // 存储一些随机数 printf("\n%d random numbers between 0 and 0000:\n", ARR_LEN); for ( i=0; i< ARR_LEN; ++i ) // 循环输出 { printf("%6d",pNumbers[i]); // 每次循环输出一个数字 if ( i % 10 == 9) putchar( '\n'); // 每10个数字换一行 } free( pNumbers ); // 释放存储空间 return 0; }
自动类型转换
强制类型转换
int total;
total=(int)10.9+(int)12.7+(int)11.8;
输出33
而
int total=10.9+12.7+11.8;
输出35 自动转换的。
10.9+12.7+11.8=35.4 为双精度浮点型,而左值 total 类型为整型,将 35.4 自动转换为整数 35
声明一个方法使用
当方法返回值是void ,顶部必须还要像C#的委托那样定义个方法签名那种,才能调用。。。
#include <stdio.h> void count(); int main(void) { int i = 0; for (i = 0; i <= 5; i++) { count(); } system("pause"); return 0; } void count() { /*声明一个静态局部变量*/ static num = 0; num++; printf("%d\n", num); }
还有个static知识点
在该代码中,我们通过在 count() 函数里声明一个静态局部变量 num 来作为计数器。因为静态局部变量是在编译时赋初值的,且只赋初值一次,在程序运行时它已有初值。以后在每次调用函数时就不再重新赋初值,而是保留上次函数调用结束时的值。这样,count() 函数每次被调用的时候,静态局部变量 num 就会保持上一次调用的值,然后再执行自增运算,这样就实现了计数功能。同时,它又避免了使用全局变量。
C#的static不能这么用。。
在静态数据区,内存中所有的字节默认值都是 0x00。静态变量与全局变量也一样,它们都存储在静态数据区中,因此其变量的值默认也为 0。演示示例如下所示。
#include <stdio.h>
static int g_x;
int g_y;
int main(void)
{
static int x;
printf("g_x:%d\ng_y:%d\nx:%d",g_x,g_y,x);
return 0;
}
====================www.ayjs.net 杨洋 wpfui.com ayui ay aaronyang=======请不要转载谢谢了。=========
_Generic C11标准 泛型
反正我在vs2017没跑好下面例子
支持轻量级的泛型编程设计
#include <stdio.h> #include <string.h> #include <stddef.h> #include <stdint.h> #define getTypeName(x) _Generic((x),_Bool:"_Bool",\ char: "char", \ signed char: "signed char", \ unsigned char: "unsigned char", \ short int: "short int", \ unsigned short int: "unsigned short int", \ int: "int", \ unsigned int: "unsigned int", \ long int: "long int", \ unsigned long int: "unsigned long int", \ long long int: "long long int", \ unsigned long long int: "unsigned long long int", \ float: "float", \ double: "double", \ long double: "long double", \ char *: "pointer to char", \ void *: "pointer to void", \ int *: "pointer to int",\ default: "other") int main(void) { char c = 'a'; size_t s; ptrdiff_t p; intmax_t i; int arr[3] = { 0 }; printf("s is '%s'\n", getTypeName(s)); printf("p is '%s'\n", getTypeName(p)); printf("i is '%s'\n", getTypeName(i)); printf("c is '%s'\n", getTypeName(c)); printf("arr is '%s'\n", getTypeName(arr)); printf("0x7FFFFFFF is '%s'\n", getTypeName(0x7FFFFFFF)); printf("0xFFFFFFFF is '%s'\n", getTypeName(0xFFFFFFFF)); printf("0x7FFFFFFFU is '%s'\n", getTypeName(0x7FFFFFFFU)); return 0; }
extern
include <stdio.h> int max(int x,int y); int main(void) { int result; /*外部变量声明*/ extern int g_X; extern int g_Y; result = max(g_X,g_Y); printf("the max value is %d\n",result); return 0; } /*定义两个全局变量*/ int g_X = 10; int g_Y = 20; int max(int x, int y) { return (x>y ? x : y); }
代码中,全局变量 g_X 与 g_Y 是在 main 函数之后声明的,因此它的作用范围不在 main 函数中。如果我们需要在 main 函数中调用它们,就必须使用 extern 来对变量 g_X 与 g_Y 作“外部变量声明”,以扩展全局变量的作用域。也就是说,如果在变量定义之前要使用该变量,则应在使用之前加 extern 声明变量,使作用域扩展到从声明开始到本文件结束。
如果整个工程由多个源文件组成,在一个源文件中想引用另外一个源文件中已经定义的外部变量,同样只需在引用变量的文件中用 extern 关键字加以声明即可。下面就来看一个多文件的示例:
/****max.c****/ #include <stdio.h> /*外部变量声明*/ extern int g_X ; extern int g_Y ; int max() { return (g_X > g_Y ? g_X : g_Y); } /***main.c****/ #include <stdio.h> /*定义两个全局变量*/ int g_X=10; int g_Y=20; int max(); int main(void) { int result; result = max(); printf("the max value is %d\n",result); return 0; }
C中有一些位运算符,C#也有我很少用,两个都一样的。
C的点运算符
struct Article { long number; // 物品编号 char name[32]; // 物品名字 long price; // 物品单价(精确到美分) /* ... */ }; struct Article sw = { 102030L, "Heroes", 5995L }; sw.price = 4995L; // 将价格改为49.95
二元运算符 . 和 -> 常常被称为点运算符(dot operator)和箭头运算符(arrow operator),借助于这两个运算符,可以选择结构或联合中的成员。
点运算结果的类型,与所选择成员的类型是一样的。
运算符 -> 也可用于选择结构或联合的成员,但是箭头运算符的左操作数必须是一个指针,它指向一个结构或联合类型。右操作数是该结构或联合成员的名字。例 2 展示了运算符->的用法,同样使用例 1 所定义的结构 Article。
下面我写了一段代码,注释都有说明,这些 东西在C很重要
#include <stdio.h> #include <time.h> #include <stdlib.h> struct Article { long number; // 物品编号 char name[32]; // 物品名字 long price; // 物品单价(精确到美分) /* ... */ }; //struct Article getArticle(); // 函数原型 int main(void) { struct Article sw = { 102030L, "Heroes", 5995L }; printf("name: %s\n", sw.name); struct Article *pArticle = &sw, // 一个指向struct Article的指针 const *pcArticle = &sw; // 一个指向struct Article的只读指针 ++(pArticle->number); // 增加编号 if (pcArticle->number == 102031L) { // 正确:获取只读指针,连pcArticle.number值也变了 printf("正确 %Id \n",pcArticle->number); //102031L 引用的 } //转换 p->m 等效于(*p.m printf("正确转换 %Id \n", (*pcArticle).number); //x.m 等效于(&x)->m printf("正确转换2 %Id \n", (&sw)->number); //优先级 ++p->m 等同于 ++(p->m) //p->m++ 等同于(p->m)++ // *p.m 等效于 *(p.m) //创建一个数组,10个 article struct Article arrArticle[10]; //一个数组名称,本例中的 arrArticle,是一个指向第一个数组元素的常量指针 arrArticle[2].price = 990L; // 设置数组元素arrArticle[2]的成员price arrArticle->number = 10100L; // 设置数组元素arrArticle[0]的成员number //所以 arrArticle->number 指向第一个数组元素的成员 number。简单地说,对于任一的索引值 i,下面 3 个表达式是等价的: //arrArticle[i].number //(arrArticle + i)->number //(*(arrArticle + i)).number //它们都指向数组中索引值为 i 的元素的成员 number。 arrArticle->name[1] = 'a'; printf("%c", arrArticle ->name[1] ); //pcArticle->price += 50; // 错误:不能使用限定符const的指针来修改对象 system("pause"); return 0; }
getchar()和scan_f 的例子,控制台输入
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int main(void)
{
int a;
char ch;
while (1)
{
printf("请输入一个数字:");
scanf_s("%d", &a);
printf("a = %d\n", a);
printf("您想继续吗(Y/N):");
getchar(); /*用getchar吸收回车, 简单、方便、好用, 都不需要定义变量用来存储获取的回车符*/
ch = getchar(); //用getchar从缓冲区中读取一个字符赋给字符变量ch
if (('Y' == ch) || ('y' == ch))
{
}
else
{
break; // 跳出本层循环体
}
}
system("pause");
return 0;
}
还有fflush替代getchar(),但是 fflush 有一个问题,就是可移植性。并不是所有的编译器都支持 fflush,比如 gcc 就不支持。那么此时怎么办?还是用 getchar()。
fflush(stdin);
//while (getchar() != '\n');
使用goto跳到书签,变量名: 冒号
#include<stdio.h> int main (void){ int n; pos_1: printf("请输入一个正整数:"); scanf("%d",&n); if(n<0) { printf("输入错误!\n"); goto pos_1; } printf("成功输入正整数:%d\n",n); return 0; }
这个setjump和longjump 不看了。书签是当前方法 内的,方法外定义用这两个
int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int value);
示例,
#include <stdio.h> #include <setjmp.h> jmp_buf buf; void F2(void) { printf("F2()\n"); longjmp(buf,1); } void F1(void) { F2(); printf("F1()\n"); } int main(void) { int jmpret = setjmp(buf); if(!jmpret) { F1(); } else { printf("继续执行main\n"); } return 0; }
F2()
继续执行main
我看不懂。。,
推荐您阅读更多有关于“C,”的文章
以上所述就是小编给大家介绍的《写给自己的用VS2017学C语言[2]》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。