发新话题
打印

[原创]C语言蛛丝计划 学习中我所看见的细节总结(第三部分)

[原创]C语言蛛丝计划 学习中我所看见的细节总结(第三部分)

文章作者:冰血封情[E.S.T]
信息来源:邪恶八进制信息安全团队(www.eviloctal.com

虽然只是一个小小的学习总结 和dahubaobao这种超级色狼比 我当然不够NB了 但是这笔记至少证明我没偷懒 仍然在学习 这一阶段的学习十分感谢邪恶八进制技术顾问团的无锋之刃和邪恶八进制成员Bideyore的帮助 总算坚持了下来:)
其实呀 看我这个SB总结 还不如买本《C 陷阱与缺陷》
理由么 很简单 我的总结是给偶自己看的 而《C 陷阱与缺陷》是14年来18次印刷屹立不倒 专门给程序员和C学习者看的

013数组的声明
这里先总结两个问题 首先数组下标是0到n-1 这是废话
下一个 需要注意的细节是 声明数组的时候 可以使用int array[10]这样声明 也可以使用
#define FUCK 10
int array[FUCK]
声明一个和int array[10]一样的数组 关键的来了 书上说 对于大多数编译器来说 不能使用const关键字定义的符号常量来指定元素数目
既然是大多数 我用VC6测试了一下 发觉可以 比如下面的程序 是VC6下可以编译运行通过的
复制内容到剪贴板
代码:
//preprocess directive
#include <stdio.h>

const int MAX = 13;

float expenses[MAX];
int count;

int main(void)
{
    //input data from keyboard into array

    for ( count = 1; count < 13; count++ )
    {
       printf("Enter expenses for month %d: ", count);
       scanf("%f", &expenses[count]);
    }

    //print array contents

    for ( count = 1; count < 13; count++ )
    {
       printf("Month %d = $%.2f\n", count, expenses[count]);
    }
    return 0;
}
014指针和简单变量的理解
我是第二遍看书才理解的 首先在这里*充当间接运算符 &是地址运算符
好了 现在我的理解是 如果情况是如下图
1000 1001 1002 1003 1004 1005 <-----------内存地址
|  |1004|  |  |100 |  | <-----------内存单元
    |       |
ptr_fuck和&fuck  fuck和*ptr_fuck
先看如下代码 都是一些关键语句
int fuck, *ptr_fuck; //整型变量fuck和指向整型变量的指针ptrname
fuck = 100; //给fuck这个变量赋值100
ptr_fuck = &fuck //把fuck的地址赋给ptr_fuck
下面说说剩下的
*ptr_fuck的值等于fuck的值等于100 而ptr_fuck的值等于&fuck的值等于fuck的地址

015作为指针的数组名
不带方括号的数组名是一个指针 它指向数组的第一个元素 data和&data[0]是等价的
而且数组名是一个指针常量 不能被修改的
对于未被初始化的指针而言 赋值语句左边是最危险的地方 比如你生命了int *ptr但是你没对它初始化 那么鬼知道他指向什么地方
如果你又*ptr = 13这样就把13赋值给了ptr指向的地址 天知道那有什么重要的资料被覆盖 所以一定要小心
因为指针储存的是变量的地址 而变量每次运行程序的时候地址是不一定的 所以如果把常量赋值给指针是很危险的

016有关malloc需要注意的事项
注意为存储字符串的时候 申请的空间应该多一个空间用于存储空字符
malloc函数返回一个指向分配的内存的指针 如果malloc无法分配所需要的内存数量 则返回null 因此每当你试图分配内存的时候都因该检查返回值 即使要分配的内存量很小 也要注意
标准
ptr = malloc( 100 * sizeof(char) )使用sizeof可以保证代码的可移植性
最后注意 一定要记得释放资源free(ptr) free函数将分配的资源归还给操作系统 下面是一个malloc的例子:
复制内容到剪贴板
代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <process.h>

int main(void)
{
    char *str; //声明一个字符型指针

    if(( str = (char *) malloc( 10 * sizeof(char)) ) == NULL) //分配地址
    {
       perror("Shit no enough!");
       return 1; //妈的原来的程序用exit 1;
    }
    strcpy(str, "Hello"); //存储Hello到刚才的地址

    printf("String is %s\n", str); //检查存储状况

    free(str); //释放她妈的资源
    return 0;
}
017输入字符串的一些总结
我暂时接触到了两个接受输入字符串的方法 一个是gets()一个scanf()
在gets中最应当注意到的是 输入的时候是读到回车结束 由于并非能总知道gets函数将读取多少字符 可能会一直输入 这可能导致超出缓冲区的末尾 因此使用它一定要小心
而用gets还有一个危险 出在指针上 看似也和安全相关 请先看如下的一点代码
char *ptr;
gets(ptr);
指针ptr被声明后没有初始化 天知道指向什么鸟地方 这个时候用gets有可能覆盖重要的文件 所以要小心使用
下面我们说说scanf这个函数
PS 本来是想总结的 结果又看了一遍书 发觉我太SB了
这些问题都归结为一类 scanf是通过空白字符来决定是否结束字符串输入的 但是要注意 它可以定义长度 比如%3c就是长度三的 如果长了就不读

最后说说 这两个函数其实都有返回值的 只是以前我菜 书上就没说
gets函数返回一个char指针 该指针指向输入字符串的存储地址 通过这样的返回值gets可以帮助程序检查是否输入的空行 比如
while ( *(ptr = gets(input)) != NULL
其中input是声明了的数组 ptr是字符型指针 NULL可以判断是否是一个空字符 如果只是回车 那么没有字符串被存储了 结束输入的时候在末尾加空字符结束字符串 那么就只有\0了 因此判断成功
scanf函数返回的是成功输入字符串的数目

018三种存取结构成员的方式
指针果然是C里最麻烦的东东 学到结构这章的一半 我看见了创建指向结构的指针这个话题
书本上告诉我 在学习到这里的时候 我们就有了三种存取结构成员的方式 分别如下:
1 通过结构名 比如
struct fuck {
    int girl;
    int boy;
} eviloctal;
这个时候就可以通过eviloctal.girl来存取结构成员
2 通过指向结构的指针和间接运算符 比如
struct fuck {
    int girl;
    char name[20];
};
struct fuck *ptr;
struct fuck eviloctal;
ptr = &eviloctal;
这个时候可以通过(*ptr).girl = 100来存取结构成员
这里说一下 之所以要用括号 是因为.的优先级高于*所以得这样
3 通过指向结构的指针和间接成员运算符 比如
struct fuck {
    int girl;
    char name[20];
};
struct fuck *ptr;
struct fuck eviloctal;
ptr = &eviloctal;
这个时候使用ptr -> girl也可以哦
qq310926是我唯一用号,除此之外有其他号码号自称邪八冰血封情,则非本人。

TOP

“不带方括号的数组名是一个指针 它指向数组的第一个元素 data和&data[0]是等价的”
这句话后半部分不完全对。
data和&data[0]只是“等值”的,不完全等价,视上下文代码而定。
对待处女,谁污染,谁治理。 对待内存,谁分配,谁释放。

TOP

引用:
下面是引用无锋之刃于2005-03-13 12:28发表的:
“不带方括号的数组名是一个指针 它指向数组的第一个元素 data和&data[0]是等价的”
这句话后半部分不完全对。
data和&data[0]只是“等值”的,不完全等价,视上下文代码而定。
无锋大哥请详细说说 我想知道的说
曾几何时,有人对我说:装B遭雷劈。我说:去你妈的。于是,这个人又对我说:如果再说脏话,上帝会惩罚你的。我说:我操上帝。结论:彪悍的人生不需要上帝。

TOP

原来有点说错了,data和&data[0]在理论上是等价的。但data与&data及data[0]都不完全等价。数组与指针经常搞混,我也不能幸免:(。

对于一维数组来说,
int data[10]
中data的严格数据类型应该是int [10],而data[0]的类型是int。但编译器很少对数组越界做检查(比如写data[11]也能通过编译器:()。这样可以看出,data的类型已经退化为int *。
而&data[0]的类型也刚好是int *。所以在这种情况下,二者等值也等价。

对于二维数组来说,
int data[10][10]
中data的严格数组类型应该是int [10][10]。但实际上它也会退化,形成int (*)[10]。而&data[0]的类型其实应该是int (*)[10](从C++的角度来看,二维数组是“元素为一维数组的数组”)。在这种情况下,有些编译器是将二者等同起来的。
对待处女,谁污染,谁治理。 对待内存,谁分配,谁释放。

TOP

前几天写DNS RPC那个exp的时候,还不小心直接memcpy shellcode的时候,长度写的sizeof(shellcode)结果就过了个0,呵呵,写c确实要小心啊。
http://www.icylife.net

TOP

发新话题