当前位置:早雪网网络学院编程文档C/C++ → 指针详解-02

指针详解-02

减小字体 增大字体 作者:不详  来源:supcode.com收集整理  发布时间:2005-7-22 19:41:22
法的地址,否则的话,在你使用ptr的时候,就会出现非法操作错误。    
    想想能不能反过来,把指针指向的地址即指针的值当作一个整数取出来。完全可以。下面的例子演示了把一个指针的值当作一个整数取出来,然后再把这个整数当作一个地址赋给一个指针:
例十六:
int a=123,b;
int *ptr=&a;
char *str;
b=(int)ptr;//把指针ptr的值当作一个整数取出来。
str=(char*)b;//把这个整数的值当作一个地址赋给指针str。
    好了,现在我们已经知道了,可以把指针的值当作一个整数取出来,也可以把一个整数值当作地址赋给一个指针。

九。指针的安全问题
    看下面的例子:
例十七:
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"); 
    }
}

上一页  [1] [2] 


Tags:指针,详解
[数据载入中...] [返回上一页] [打 印]