一些小练习

1. 指针参数

void f(char *p)

{

    p=(char *)malloc(10);

}

int main()

{

char *p=NULL;

f(p);

free(p);

return 0;

}

free(NULL)是可以的,只是指针变量做函数参数仍然是单向的值传递,p指针仍然是0,所以这里内存泄露了。

2.字符数组

char s1[24]="how are u";

char s2[24]="how are you";

int i,len = strlen(s2);

for (i=0;i<len;i++)

  s1[i]=s2[i];

printf("s1=%s s2=%s/n",s1,s2);

这里s1和s2都能正常显示,因为s1后面全是自动补0.

3.void指针转换

class A
{
public:
    A():a(2),p((void *)5)
    {
        printf("a=%d p=%d/n",a,p);
    }
    int a;
    void *p;
};
int main()
{
    A b;
}

这里p一定要用(void *)强制转换,但p的值是5,引用它会造成系统受影响。

4.堆内存,数据段,代码段

#include <stdio.h>
char *f1()
{
char a[]="Hello, world!!";
return a;
}
char *f2()
{
char *a="Hello, world!!";
return a;
}
char *f3()
{
      static char *a="Hello, world!";
      return a;
}
void main()
{
char *s1;
char *s2;
char *s3;
s1=f1();
s2=f2();
s3=f3();
puts(s1);
puts(s2);
puts(s3);
}
一个程序在内存中,按照内存地址从低到高的顺序,分布着代码段、常量段、数据段、 堆内存和 栈内存
 
代码段 用来存放程序的机器码
常量段 用来存放所有的字符串常量
数据段 用来存放全局变量和静态变量(这个段在程序加载后自动清0,这就是为什么全局变量和静态变量的初始值都是0)
代码段、常 量段和数 据段内存都是和程序的生命周期相同的,只有程序结束后,该内存才会被释放。数据段又分为已初始化数据段未初始化数据段 , 未初始化数据段不影响目标文件的大小。
堆内存 ,程序中用malloc等内存分函数申请的内存块,从数据段顶端开始,从低地址向高地址分配。必须调用free等内存释放函数,将不使用的内存释放。
栈内存 ,存放函数内的临时变量,程序每进入一个函数前,从栈内存内分配一块内存,大小等于该函数内的临时变量的大小,当函数结束后,该内存被自动释放。栈内存从 高地址向低地址方向分配。
堆内存和栈 内存在被 分配出去后是不会重新初始化的,所以分配的时候内存中放的什么数据,你得到的内存中就是什么数据。这就是为什么临时变量和malloc的内出中的数据是随 机值 的原因。
下面我们来看看前面提到的几种情况:
1) . char a[] = " Hello,world! ";
a是局部字符数组变量,数组大小为13,数组内的元素被初始化为"Hello,world! /0 "。
a被存储在函数f1的栈内存中,return a将a的首地址返回回去了。f1函数结束后,f1的栈内存被释放,原来a所在的内存地址可能被挪做它用,所以那个地址里面放的是什么东西不得而知,因此 puts输出该地址中的内容得到的结果是随机的。
2 ) . char *a = " Hello,world! ";
a是一个char*指针变量,大小为4个字节,其值是" Hello,world! "这个常量字符串的首地址。 " Hello,world! "常量字符串被保存在常量段,不能被更改。
a被存储在函数f1的栈内存中,return a返回的是指针a的值,即 " Hello,world! "常量字符串的首地址。f1函数结束后,a被释放了,但a 指向的常量段的内容没有变。因此puts输出是正确的。
3 ) . static char a[] = " Hello,world! ";
a是静态字符数组变量,数组大小为13,数组内的元素被初始化为"Hello,world! /0 "。
a被存储在数据段内,return a将a的首地址返回回去了。f1函数结束后,a所在的内存不会被释放,因此puts输出该地址中的内容得到的就是a中存储的字符串。

5.单链表反转

struct tagT
{
   int data;
   struct tagT *next;
};

typedef struct tagT T;

T *revert(T *head)
{
   T *p=head, *pnext=NULL, *newHead=NULL;
  while(p!=NULL)
  {
      pnext=p->next;
      p->next=newHead;
      newHead=p;
      p=pnext;
  }
  return newHead;
}

T *insert(T *head, int data)
{
    T *newNode = (T *)malloc(sizeof(T));
    memset(newNode,0,sizeof(T));
    newNode->data = data;
    newNode->next = NULL;

    T *p=head;
    if ( NULL == p )
    {
          /* no one node */
          return newNode;
    }
    else
    {
        /* point to end */
        while ( p->next!=NULL )
       {
          p=p->next;
        }
        /* insert */
        p->next = newNode;
        return head;
     }
}

void print(T *head)
{
     T *p=head;
     while (p!=NULL)
    {
        printf("%2d ", p->data);
        p=p->next;
    }
    printf("/n");
}

int main()
{
    T *head = NULL;
    head = insert(head,1);
    head = insert(head,2);
    head = insert(head,3);
    print(head);

    head = revert(head);
    print(head);

    return 0;
}

6.两个大数相乘

char *multi(char *a, char *b)
{
    int n=strlen(a), m=strlen(b);
    int i=0,j=0;
    int temp=0;
    int *c=(int *)malloc(sizeof(int)*(n+m));
    memset(c,0,(n+m)*4);

    for ( i=0;i<n;i++)
        for (j=0;j<m;j++)
            c[i+j+1]+=(a[i]-'0')*(b[j]-'0');


    for ( i=n+m-1;i>=0;i--)
    {
        if ( c[i]>=10 )
        {
            c[i-1]+=c[i]/10;
            c[i]=c[i]%10;
        }
    }

    char *p, *result=(char *)malloc(n+m+1);
    memset(result,0,
n+m+1 );
    i=0;
    while (c[i]==0)
        i++;
    p=result;
    for (;i<n+m;i++,p++)
        (*p)=(c[i]+'0');
    return result;

}

7.用预处理指令

#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL

8.写一个“标准”宏MIN

这个宏 输入两个参数并返回较小的一个。
#define MIN(A,B) ((A) <= (B) ?(A) : (B))

再看下面一个例子,输出是多少呢

    #define MAX(A,B) ((A) >= (B)?(A):(B))

    int b=3,a=4;
    int *p=&a;
    int least = MAX((*p)++,b);
    printf("least=%d a=%d b=%d/n", least,a,b);

这个结果是,5,6,3,这就是宏定义的副作用,三目运算符可以看成2个表达式,前面一个已经

把a加1了,然后赋值给least。另外,这里*p++表达式,++的级别要高于*,所以要加括号。

9. 关键字volatile有什么含意 并给出三个不同的例子。

的变量是说这变量可能会被意想不到地改变,

下面是volatile变量的几个例 子:
1). 并行设备的硬件寄存器(如:状态寄存器)
2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3). 多线程应用中被几个任务共享的变量

int square(volatile int *ptr)
{
return *ptr * *ptr;
}

编译器将产生类似下面的代码:
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}

应该为

long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}

10. 位操作

写两段代码,第一个设置a的bit 3,第二个清除a 的bit 3。在以上两个操作中,要保持其它位不变。

#define BIT3 (0x1<<3)

a |= BIT3;

a &= ~BIT3;

11. 指针地址

要求设置一绝对地址为0x67a9的整 型变量的值为0xaa66

一个整型数 转化成 一指针需要强制转换

short *ptr;
ptr = (
short *)0x67a9;
*ptr = 0xaa55;

12 . 类型提升

下面的代码输出是什么,为什么?

void foo(void)
{
     unsigned int a = 6;
     int b = -20;
     (a+b > 6) puts("> 6") : puts("<= 6");
}

当表达式中存在有符号类型和无符号类型 时所有的操作数都自动转换为无符号类型。因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6

13. 评价下面的代码片断

unsigned int zero = 0;
unsigned int compzero = 0xFFFF;
/*1's complement of zero */

对于一个int型不是16位的处理器为说,上面的代码是不正确的。应编写如下:

unsigned int compzero = ~0;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值