所有代码均为曾经学习过程中不清楚不或明白的问题,做的验证,拿出来分享,文章有点长哦
内容涉及(按文章中的先后顺序):argc和argv;const;getmemory;各种数据类型所占用内存大小;pragma和error;sizeof(*p)和sizeof§;sizeof和strlen;void指针;volatile;while(–a)和while(a–);单链表;双链表;猴子吃桃;阶乘;矩阵乘法;类型转换;冒泡选择排序;大小端;数组首地址表示方法;数组作为结构体变量;数组作为结构体成员;数组作为形参;野指针;指针访问二维数组;指针分配动态内存;指针函数与函数指针;指针数组;质数、最小公倍数、最大公约数、闰年;字符串逆序输出;字符串常量与字符数组;
1.argc和argv
//#include "stdafx.h"
//#include "iostream"
#include<stdio.h>
//using namespace std;
int main(int argc, char* argv[])
{
int i;
for (i = 0; i < argc; i++)
{
//cout << "argument" << i << ": " << argv[i] << endl;
printf("argv[%d] = %s\n",i,argv[i]);
}
//cout << "total argument:" << argc;
printf("argc = %d\n", argc);
//return EXIT_SUCCESS;
return 0;
}
*/
/*
两个参数中第一个参数argc表示在Dos命令行中的输入的程序名和参数个数之和,第二个参数中argv[0]记录的程序名,后面的argv[i]记录的输入参数。
另外argc argv是标识符,可以修改名称。
*/
2.const
/*
#include<stdio.h>
int main(void)
{
const int a = 12;
const int* p = &a;
p++;
&b;
t++;
p = &b;
q = &b; p--;
int const* q = &a;
int b = 12;
int* const r = &b;
r++;
const int* const t =
return 0;
}
*/
/*
#include<stdio.h>
int main()
{ const int a = 12;
const int* p = &a; //这个是指向常量的指针, 指针指向
一个常量
p++; //指针可以自加、 自减
p--; //合法
int const* q = &a; //这个和上面的“const int*p=&
a; ”是一个意思
int b = 12;
int* const r = &b; //这个就是常量指针(常指针) , 不
能自加、 自减, 并且要初始化
//r++; //编译出错
const int* const t = &b; //这个就是指向常量的常指
针, 并且要初始化, 用变量初始化
//t++; //编译出错
p = &b; //const指针可以指向const和非const对象
q = &b; //合法
return 0;
}
*/
/*
#include<stdio.h>
int main(void)
{
int a = 12;
int b = 13;
//第一种
//const int* p = &a; //或者int const*p=&a; 指向常量的指针,指针的地址可以改,但不能对指针内的数据进行改动,因为这时* p 是一个常量,但 指针p 可以改动
//可以在后面这么写,(1) p = &b; (2) a = 13; (3)p++;这三种是合法的 不合法的一种为(1)*p=13;
//第二种
int* const p = &a; //常量指针,指针p为常量,此时指针p为常量,所指向的地址不能改动,但指针所指地址数据可以改动
//可以在后面这样写,(1)a=13; (2)*p=13;这两种都是合法的 不合法的两种为(1)p = &b; (2)p++;
//第三种
//const int* const p= &a; //指向常量的常指针,并且要初始化,用变量初始化,*p 指针p都是只读的,不可改动
//可以在后面这样写,(1)a=13;这种是合法的,不合法的三种为(1)p = &b; (2)*p = 13; (3)p++;
//a = 13;
//p = &b;
//*p = 13;
//p++;
printf("%d\n", *p);
}
*/
3.getmemory
//#pragma warning( disable : 4996)
/*
void getmemory(char *p)
{
p=(char *) malloc(100);
strcpy(p,"hello world");
}
int main( )
{
char *str=NULL;
getmemory(str);
printf("%s/n",str);
free(str);
return 0;
}
程序崩溃,getmemory中的malloc 不能返回动态内存, free()对str操作很危险
77、void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
请问运行Test函数会有什么样的结果?
答:程序崩溃。因为GetMemory并不能传递动态内存,Test函数中的 str一直都是 NULL。strcpy(str, "hello world");将使程序崩溃。
void GetMemory2(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
请问运行Test函数会有什么样的结果?
答:(1)能够输出hello
(2)内存泄漏,因为忘记free
78、char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
请问运行Test函数会有什么样的结果?
答:可能是乱码。因为GetMemory返回的是指向“栈内存”的指针,该指针的地址不是 NULL,
但其原先的内容已经被清除,新内容不可知。
---------------------------------------
下面程序运行有什么样的结果?
char *GetString(void)
{
char array[6];
strcpy(array, “hello”);
return array;
}
void main()
{
char *pstr = NULL;
pstr = GetString();
printf("%s\n", pstr);
}
答对这个问题,脑子里必须有一根弦,那就是栈内存里的内容如“昙花一现”,其有效的生命周期只等于函数周期,访问栈内存的前提条件是在函数运行范围内,函数一旦退出,相应的栈内存立马消散,如同镜花水月,再访问就是野指针的“非法”操作。
上例中,函数char *GetString返回了指向局部数组array[6]的指针,但array[6]位于栈中,函数的栈内存在其结束后立刻失效,函数退出后再试图通过pstr访问栈内存就成了非法操作。因此,返回指向栈内存的指针这种机制,看似在函数退出后继续访问栈内存留了一个“后门”,实际上是一个隐晦的陷阱。再比较下面例子:
*/
/*
#define _CRT_SECURE_NO_WARNINGS
#pragma warning( disable : 4996)
#include<stdio.h>
#include<string.h>
#include<malloc.h>
char *GetString(void)
{
char array[6]="hello";
char *p = (char *)malloc(6);
strcpy(p, array);
return p;
}
int main(void)
{
char *str = NULL;
str = GetString();
printf("%s\n", str);
free(str);
return 0;
}
这里先把hello字符串从array[]所在的栈内存拷贝到指针p指向的堆内存中,当GetString 函数结束后,array[]栈内存失效了,但指针p所指的堆内存仍有效并保存着”hello”串,函数返回指向堆的指针就没有问题了。如果把直接用指针指向字符串呢:
char *GetString(void)
{
char *p = "hello";
return p;
}
void main()
{
char *str = NULL;
str = GetString();
printf("%s\n", str);
}
把原先的数组修改成指针,即 char *str="hello",这样也可行,因为"hello"串位于常量数据区,在子函数结束后依然有效,通过返回的p指针仍然可以读取这块内存。
栈本身主要是由编译器静态维护和管理,所以程序中一般情况下应该避免使用指向栈的指针
---------------------------------------------
79、void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, “hello”);
free(str);
if(str != NULL)
{
strcpy(str, “world”);
printf(str);
}
}
请问运行Test函数会有什么样的结果?
答:篡改动态内存区的内容,后果难以预料,非常危险。因为free(str);之后,str成为野指针,
if(str != NULL)语句不起作用。
野指针不是NULL指针,是指向被释放的或者访问受限内存指针。
造成原因:指针变量没有被初始化任何刚创建的指针不会自动成为NULL;
指针被free或delete之后,没有置NULL;
指针操作超越了变量的作用范围,比如要返回指向栈内存的指针或引用,因为栈内存在函数结束时会被释放。
*/
4各种数据类型所占用内存大小
/*
#include<stdio.h>
#include<stdlib.h>
int main()
{
int n = 0; //整型
char ch = 0; //字符
int arr1[5] = { 0 }; //整型数组
char arr2[5] = { 0 }; //字符数组
int* p1 = &n; //整形指针
char* p2 = &ch; //字符指针
int* p3 = arr1; //整形指针
char* p4 = arr2; //字符指针
int(*p5)[5] = &arr1; //整形数组指针
char(*p6)[5] = &arr2; //字符数组指针
int* arr3[5] = { p1 }; //整形指针数组
char* arr4[5] = { p2 }; //字符型指针数组
printf("int占%d个字节\n", sizeof(int));
printf("short占%d个字节\n", sizeof(short));
printf("char占%d个字节\n", sizeof(char));
printf("long占%d个字节\n", sizeof(long));
printf("float占%d个字节\n", sizeof(float));
printf("long long占%d个字节\n", sizeof(long long));
printf("double占%d个字节\n", sizeof(double));
printf("整形变量占%d个字节\n", sizeof(n));
printf("字符变量占%d个字节\n", sizeof(ch));
printf("整形数组 int [5] 占%d个字节\n", sizeof(arr1));
printf("字符数组 char [5] 占%d个字节\n", sizeof(arr2));
printf("整形指针 int* 占%d个字节\n", sizeof(p1));
printf("字符指针 char* 占%d个字节\n", sizeof(p2));
printf("整形数组指针 占%d个字节\n", sizeof(p5));
printf("字符数组指针 占%d个字节\n", sizeof(p6));
printf("整形指针数组 占%d个字节\n", sizeof(arr3)); //指针4个字节,数组5个字节4*5=20
printf("字符指针数组 占%d个字节\n", sizeof(arr4)); //指针4个字节,数组5个字节4*5=20
printf("指向整形数组的指针 占%d个字节\n", sizeof(p3));
printf("指向字符数组的指针 占%d个字节\n", sizeof(p4));
//system("pause");
return 0;
}
*/
/*
#include<stdio.h>
#include<stdlib.h>
int main()
{
printf("int占%d个字节\n", sizeof(int));
printf("short占%d个字节\n", sizeof(short));
printf("char占%d个字节\n", sizeof(char));
printf("long占%d个字节\n", sizeof(long));
printf("float占%d个字节\n", sizeof(float));
printf("