写给自己的用VS2017学C语言[2]

栏目: C · 发布时间: 6年前

内容简介:每个标准库函数都会被声明在一个或多个标准头(standard header)中。每个标准头都包含一组相关的函数声明、宏和类型定义。例如,数学函数声明在头文件 math.h 中。标准头也称之为头文件(header file)

每个标准库函数都会被声明在一个或多个标准头(standard header)中。

每个标准头都包含一组相关的函数声明、宏和类型定义。例如,数学函数声明在头文件 math.h 中。标准头也称之为头文件(header file)

写给自己的用VS2017学C语言[2]

C 程序只会在两种运行环境中执行:宿主(hosted)环境或独立(freestanding)环境

vs上是宿主的,独立的我猜是写入硬件吧,估计使用的库也少。

发现C中的printf打印字符串,对类型必须 必须正确 ,不存在C#的隐式转换。比如输出的一个数字,不用ToString(),C中的字符串是%s,数字%d 浮点%f

标准库的函数不一定确保可重入(reentrant)。也就是说,在一个进程中两次调用同一个函数并行执行可能是不安全的行为。之所以制定该规则,其中一个原因是:部分标准函数会使用和修改同一个静态变量或线程变量。

因此,你不能在信号处理进程(signal handling rountine)中调用标准库函数。信号是异步的,也就是说,程序可能在任何时候收到信号,甚至是正在执行标准库函数时。当发生这种情况时,如果信号处理器再调用的标准函数与正在执行的是同一个,那么该函数则必须是可重入的。

线程安全(thread-safe):可以“同时”被几个线程安全地执行

如果头文件的定义的函数名 与内置的一些函数重名,可以

#undef 取消

写给自己的用VS2017学C语言[2]

把名称放在括号内,也可以调用函数而非宏:

#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输出

写给自己的用VS2017学C语言[2]

从输出结果可以看出:如果是小写的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();

写给自己的用VS2017学C语言[2]

综上所述,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[];  // 外部声明

写给自己的用VS2017学C语言[2]

写给自己的用VS2017学C语言[2]

写给自己的用VS2017学C语言[2]

标准库的头文件针对特定用途定义了很多整数类型,例如用来显示宽字符的 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;
}

自动类型转换

写给自己的用VS2017学C语言[2]

强制类型转换

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没跑好下面例子

支持轻量级的泛型编程设计

写给自己的用VS2017学C语言[2]

#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]》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

OKR工作法

OKR工作法

克里斯蒂娜•沃特克 (Christina Wodtke) / 明道团队 / 中信出版社 / 2017-9-1 / CNY 42.00

《OKR工作法》讲述了一种风靡硅谷科技企业的全新工作模式。 如何激励不同的团队一起工作,全力以赴去实现一个有挑战性的目标? 硅谷的两个年轻人汉娜和杰克,像很多人一样,在萌生了一个创意后,就走上创业之路。但是,很快他们发现好的想法远远不够,必须还有一套适合的管理方法确保梦想能实现。为了让创业团队生存下来,汉娜和杰克遭受了内心的苦苦挣扎和煎熬。他们患上“新奇事物综合症”,什么都想做,导致无......一起来看看 《OKR工作法》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具