C语言中的main函数参数及返回值

开发中遇到了需要传参数给main函数的问题,不常用,也就不记得了,特意查了一下,参考这里

一个简单的C语言例子,如下(例子来源于参考网站):

int main(int argc, char *argv[])
{
   int i;
   for (i = 1; i < argc; i++)
       printf("%s%s", argv[i], (i < argc-1) ? " " : "");
   printf("\n");
   return 0;
}

程序编译后,添加参加如:c:\demo.exe hello,world

程序就会运行出来结果:

hello,world

C语言约定:argv[0]的值是启动该程序的程序名,因此argc的值至少为1,如果argc的值是1,说明程序名后面没有命令行参数。

Read More →

关于 xxxx.exe 中的 0xxxxxxxx 处最可能的异常: 0xC0000005: 读取位置 0xxxxxxxx 时发生访问冲突

参考:http://www.cnblogs.com/lin1270/archive/2013/04/17/3025831.html

多线程调试直接崩溃,没有堆栈调用,很难查问题,只有一个错误提示框,类似于“关于 xxxx.exe 中的 0xxxxxxxx 处最可能的异常: 0xC0000005: 读取位置 0xxxxxxxx 时发生访问冲突”,参考上述站点,把堆栈调出来的方法,MARK:

工具栏上的【调试】->【异常】,把图上显示的【引发】勾上即可。

Read More →

数组名和数组名取地址的区别

一直困惑了很久的一个问题,今天终于解决了,参考:http://blog.csdn.net/daniel_ice/article/details/6857019

#include <stdio.h>

int a[2] = {1,2};
int main(){
        printf("a = %p\n", a); // I
        printf("&a = %p\n", &a); // II
        printf("a + 1 = %p\n", a + 1);// III
        printf("&a + 1 = %p\n", &a + 1);// IV

        return 0;
}
//结果如下(Windows):
//a = 01137034
//&a = 01137034
//a + 1 = 01137038
//&a + 1 = 0113703C

在C中, 在几乎所有使用数组的表达式中,数组名的值是个指针常量,也就是数组第一个元素的地址。 它的类型取决于数组元素的类型: 如果它们是int类型,那么数组名的类型就是“指向int的常量指针“。

看到这里我想应该就知道为什么 会有I 和 III式的结果了。

对于II 和 IV 则是特殊情况,在《C和指针》p142中说到,在以下两中场合下,数组名并不是用指针常量来表示,就是当数组名作为sizeof操作符和单目操作符&的操作数时。 sizeof返回整个数组的长度,而不是指向数组的指针的长度。 取一个数组名的地址所产生的是一个指向数组的指针,而不是一个指向某个指针常量的指针。

所以&a后返回的指针便是指向数组的指针,跟a(一个指向a[0]的指针)在指针的类型上是有区别的。

Read More →

字符串常量到底存放在哪个存储区

参见搜索做的总结,原文地址如下:http://blog.csdn.net/daiyutage/article/details/8605580

一直有一个疑惑,字符串常量放在哪个存储区呢?比如:

char *pstr = "hello world!";

这里,"hello world!"是一个字符串常量,pstr是在栈中的变量,字符串常量(hello world!),如何存储?举个例子,比较清晰。

//main.cpp
int a = 0; //全局初始化区
char *p1; //全局未初始化区
main()
{
    int b; //栈
    char s[] = "abc"; //栈
    char *p2; //栈
    char *p3 = "123456"; //123456\0在常量区,p3在栈上。
    static int c = 0; //全局(静态)初始化区
    p1 = (char *)malloc(10);
    p2 = (char *)malloc(20);
    //分配得来得10和20字节的区域就在堆区。
    strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}

上面例子说得比较全了,之前还以为char s[] = "abc"; 这里的abc也是在常量区,too young, too simple啊。

下面总结的一些常识,很形象,很生动,MARK一下。

Read More →

逗号表达式

逗号表达式,不常用,安全软件编码中也不允许使用,百科的解释比较到位:

c语言提供一种特殊的运算符,逗号运算符,优先级别最低,它将两式联接起来,如:(3+5,6+8)称为逗号表达式,其求解过程先表达式1,后表达式2,整个表达式值是表达式2的值,如:(3+5,6+8)的值是14。(a=3*5,a*4)的值是60。

看两个例子就能明白,这两个例子都是告诉我们,逗号运算符的优化级比赋值号还低。

main()
{
    int a, b, c, d;        
    a = 3;
    b = 5;
    c = a, b;
    d = (a, b);
    printf(" c = % d & quot; , c);
    printf(" d = % d & quot; , d);
}
//结果是 3 5

 

main()
{
    int x, y, z;
    x = y = 1;
    z = x++, y++, ++y;
    printf("%d,%d,%d\n", x, y, z);
}
//结果是 2 3 1 

Read More →

指针和数组要深入理解

一直忙于干活,很多知识都遗忘了,遇到一段代码,发现自己的基础太令人捉急了,代码类似于:

main()
{
    int a[5] = {1, 2, 3, 4, 5};
    int *ptr = (int *)(&a + 1);
    printf("%d %d" , *(a + 1), *(ptr - 1));
}

结果应该是2 5,原因在于(int*)(&a+1)这里。


2013/12/10 22:51 update:

指针和数据很多时候混用,但不代表两者相同,另外,很重要的一点,如果一个数组声明为指针时,定为成数组时,如下:

extern int *a;//声明

int a[0] = {0,1};//定义

在使用extern的文件中,若使用a[0]的方式来访问,就会出现错误,原因是编译以声明作为编译的依据,定义可以看作是一种特殊的声明,是分配内存,甚至初始化的功能。用指针去访问数组,存在二次寻址的过程,但是例子中的指针a并不存在一个额外的内存地址用来存放指针变量,所以编译器会把a[0]翻译为,先从a的内容中取内容0,再去寻找存放在地址0内的内容,这显然是不正确的,找不到地址为0的内存。

Read More →

错误的结果2...VC/bin/cl.exe返回的解决方案

研究编译器优化(选择的是完全优化)时,发现的问题,编译不通过,万能的Google一下子就搜到了,看来是常见的问题,参考:

http://blog.csdn.net/mdjtf/article/details/5617292

程序运行时弹出了一个新窗口叫做【输出】,里边写着生成日志保存某个位置,基本是在工程目录下的Debug,打开内容有:

cl: 命令行 error D8016 :“/O2”和“/ZI”命令行选项不兼容
项目 : error PRJ0002 : 错误的结果 2 (从“C:/Program Files/Microsoft Visual Studio 9.0/VC/bin/cl.exe”返回)。

经查是调试信息格式的用于“编辑并继续”的程序数据库(/ZI),改成禁用,继续。

新的错误:cl: 命令行 error D8016 :“/O1”和“/RTC1”命令行选项不兼容,此时将代码生成的基本运行时检查为默认值,就可以了。

Read More →

setjmp和longjmp函数使用详解

看到这两个函数,不认识,没用过,赶紧MARK,参考:

http://blog.csdn.net/chenyiming_1990/article/details/8683413

http://blog.codingnow.com/2010/05/setjmp.html

setjmp和longjmp函数是非局部跳转语句。非局部指的是,这和C语言常见的goto不一样,goto语句在一个函数内实施的跳转,而setjmp和longjmp是在栈上跳过若干调用帧,返回到当前函数调用路径上的某一个函数中。使用这两上函数比goto还要容易出错,<u>所以不会用在安全软件上,而且也不是C89的标准。</u>

#include <setjmp.h>  
// 返回值:若直接调用则返回0,若从longjmp调用返回则返回非0值的longjmp中的val值  
Int setjmp(jmp_buf  env);     

//调用此函数则返回到语句setjmp所在的地方,其中env 就是setjmp中的 env,而val 则是使setjmp的返回值变为val。  
Void longjmp(jmp_buf env,int val); 

当检查到一个错误时,调用longjmp函数(两个参数),第一个参数就是在调用setjmp时所用的env,第二个参数是具有非0值的val,它将成为从setjmp处返回的值。<strong>使用第二个参数的原因是对于一个setjmp可以有多个longjmp。</strong>

下面这个例子简单地讲述了这两个函数是如何使用的:

#include <stdio.h>
#include <setjmp.h>
 
static jmp_buf buf;
 
void second(void) {
    printf("second\n");         // 打印
    longjmp(buf,1);             // 跳回setjmp的调用处 - 使得setjmp返回值为1
}
 
void first(void) {
    second();
    printf("first\n");          // 不可能执行到此行
}
 
int main() {   
    if ( ! setjmp(buf) ) {
        first();                // 进入此行前,setjmp返回0
    } else {                    // 当longjmp跳转回,setjmp返回1,因此进入此行
        printf("main\n");       // 打印
    }
 
    return 0;
}
//程序将输出:
//second
//main

Read More →