扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
作者:ghost 来源:CSDN 2007年9月24日
关键字:
在本页阅读全文(共3页)
九。指针的安全问题
    看下面的例子: 
例十七: 
char s='a'; 
int *ptr; 
ptr=(int*)&s; 
*ptr=1298; 
    指针ptr是一个int*类型的指针,它指向的类型是int。它指向的地址就是s的首地址。在32位程序中,s占一个字节,int类型占四个字节。最后一条语句不但改变了s所占的一个字节,还把和s相临的高地址方向的三个字节也改变了。这三个字节是干什么的?只有编译程序知道,而写程序的人是不太可能知道的。也许这三个字节里存储了非常重要的数据,也许这三个字节里正好是程序的一条代码,而由于你对指针的马虎应用,这三个字节的值被改变了!这会造成崩溃性的错误。 
    让我们来看一例: 
例十八: 
1。 char a; 
2。 int *ptr=&a; 
... 
... 
3。 ptr++; 
4。 *ptr=115; 
    该例子完全可以通过编译,并能执行。但是看到没有?第3句对指针ptr进行自加1运算后,ptr指向了和整形变量a相邻的高地址方向的一块存储区。这块存储区里是什么?我们不知道。有可能它是一个非常重要的数据,甚至可能是一条代码。而第4句竟然往这片存储区里写入一个数据!这是严重的错误。所以在使用指针时,程序员心里必须非常清楚:我的指针究竟指向了哪里。在用指针访问数组的时候,也要注意不要超出数组的低端和高端界限,否则也会造成类似的错误。 
在指针的强制类型转换:ptr1=(TYPE*)ptr2中,如果sizeof(ptr2的类型)大于sizeof(ptr1的类型),那么在使用指针ptr1来访问ptr2所指向的存储区时是安全的。如果sizeof(ptr2的类型)小于sizeof(ptr1的类型),那么在使用指针ptr1来访问ptr2所指向的存储区时是不安全的。至于为什么,读者结合例十七来想一想,应该会明白的。 
十、指针与链表问题 
红色部分所示的程序语句有问题,改正后的程序在下面。
 list1.c 
#include 
#include 
struct listNode{ 
    int data; 
     struct listNode *nextPtr; 
}; 
typedef struct listNode LISTNODE; 
typedef LISTNODE * LISTNODEPTR; 
void list(LISTNODEPTR *, int); 
void printlist(LISTNODEPTR); 
main() 
{ 
    LISTNODEPTR newPtr=NULL; 
    int i,a; 
    for(i=0;i<3;i++){ 
        printf("please enter a number\n"); 
        scanf("%d,",&a); 
        list(&newPtr,a); 
        // 此处给的是newPtr的地址, 注意! 
      } 
      printlist(newPtr); 
    free(newPtr); 
     // 链表的释放不能这样写,这样,只释放了newPtr指向的一个节点。 
     // 可以先找到链表的尾,然后反向释放;或者,利用 printlist的顺序释放, 
     // 改函数printlist,或在此函数里释放。 
    return 0; 
} 
void list(LISTNODEPTR *sPtr, int a) 
{ 
    LISTNODEPTR newPtr,currentPtr; 
    newPtr=malloc(sizeof(LISTNODEPTR)); 
    // 此处错, LISTNODEPTR 是指针类型,不是结构类型, 
    // malloc返回void指针,应该强制转换类型,此处会告警不报错,但应有良好的编程风格与习惯。 
    if(newPtr!=NULL){ 
        newPtr->data=a; 
        newPtr->nextPtr=NULL; 
         currentPtr=*sPtr; 
    } 
    if(currentPtr==NULL){ 
     // 此处条件不确切,因为currentPtr没有初始化, 
     // 如newPtr一旦为NULL,此句及以下就有问题。 
    newPtr->nextPtr=*sPtr; 
    *sPtr=newPtr;} 
     // 在第一个数来的时候,main里的newPtr通过sPtr被修改指向此节点。 
     // 在第二个数来的时候,main里的newPtr通过sPtr被修改指向此节点。 
     // 在第三个数来的时候,main里的newPtr通过sPtr被修改指向此节点。 
     // 最后,main里的newPtr指向第三个数。 
} 
void printlist(LISTNODEPTR currentPtr) 
{ 
    if(currentPtr==NULL) 
        printf("The list is empty\n"); 
    else{ 
        printf("This list is :\n"); 
       while(currentPtr!=NULL){ 
            printf("%d-->",currentPtr->data); 
            // main里的newPtr指向第三个数。你先打印了最后一个数。
            // currentPtr=currentPtr->nextPtr->data;
            // 此句非法, 类型不同, 有可能让你只循环一次,如data为0。
       } 
       printf("NULL\n\n"); 
    } 
} 
    // 对类似程序能运行,但结果似是而非的情况,应该多利用跟踪调试,看变量的变化。 
改正后的正确程序
#include 
#include 
struct listNode{ 
    int data; 
    struct listNode *nextPtr; 
}; 
typedef struct listNode LISTNODE; 
typedef LISTNODE * LISTNODEPTR; 
LISTNODEPTR list(LISTNODEPTR , int); // 此处不同 
void printlist(LISTNODEPTR); 
void freelist(LISTNODEPTR); // 增加 
main() 
{ 
    LISTNODEPTR newPtr=NULL; 
    int i,a; 
    for(i=0;i<3;i++){ 
        printf("please enter a number\n"); 
        scanf("%d,",&a); 
        newPtr = list(newPtr,a); // 此处注意 
    } 
    printlist(newPtr); 
    freelist(newPtr); // 此处 
    return 0; 
} 
LISTNODEPTR list(LISTNODEPTR sPtr, int a) 
{ 
    if ( sPtr != NULL ) 
        sPtr->nextPtr = list( sPtr->nextPtr, a ); // 递归,向后面的节点上加数据。 
    else 
    { 
        sPtr =(LISTNODEPTR) malloc(sizeof(LISTNODE)); // 注意,是节点的尺寸,类型转换 
        sPtr->nextPtr = NULL; 
        sPtr->data = a; 
    } 
    return sPtr; 
} 
void freelist(LISTNODEPTR sPtr ) 
{ 
    if ( sPtr != NULL ) 
    { 
        freelist( sPtr->nextPtr ); // 递归, 先释放后面的节点
        free( sPtr ); // 再释放本节点 
    } 
    else // 
    return ; // 此两行可不要 
} 
void printlist(LISTNODEPTR currentPtr) 
{ 
    if(currentPtr==NULL) 
        printf("The list is empty\n"); 
    else 
    { 
        printf("This list is :\n"); 
        while(currentPtr!=NULL) 
        { 
            printf("%d-->",currentPtr->data); 
            currentPtr=currentPtr->nextPtr; // 这里不一样 
        } 
        printf("NULL\n\n"); 
    } 
} 
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1746347
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。