一个既超级简单又超级复杂的C语言问题:

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个既超级简单又超级复杂的C语言问题:相关的知识,希望对你有一定的参考价值。

程序一:
#include<stdio.h>
#include<stdlib.h>

int main()

char *s;
int nLen = 100;

// malloc申请的空间最多存储长度为100的字符串
// 最后一个字节存储字符串结尾符
s = (char *)malloc((nLen + 1) * sizeof(char));

gets(s);
puts(s);

free(s);
s = NULL;

return 0;

能够运行!
程序二:
#include<stdio.h>
#include<stdlib.h>

int main()

char *s;

s = (char *)malloc(sizeof(char));

gets(s);
puts(s);

free(s);
s = NULL;

return 0;

不能运行!

程序三:
#include<stdio.h>
#include<stdlib.h>

int main()

char *s;
s = (char *)malloc( sizeof(char));
gets(s);
puts(s);
return 0;

可以运行!

程序四:
#include<stdio.h>
#include<string.h>
int main()

char s[20]="djksafd";
char *str=s;
char s1[2];
strcpy(s1,str);
printf("%s\n",s1);
return 0;

不能运行!

程序五:
#include<stdio.h>
#include<string.h>
int main()

char s[20]="djksafd";
char *str="hakdshkdsak";
char s1[2];
strcpy(s1,str);
printf("%s\n",s1);
return 0;

可以运行!

程序六:
#include<stdio.h>
#include<string.h>
int main()

char s[20]="djksafd";
char *str=s;
char s1[20];
strcpy(s1,str);
printf("%s\n",str);
return 0;

可以运行!

程序七:
程序一:
#include<stdio.h>
#include<stdlib.h>

int main()

char *s;
int nLen = 100;

// malloc申请的空间最多存储长度为100的字符串
// 最后一个字节存储字符串结尾符
s = (char *)malloc((nLen + 1) * sizeof(char));

gets(s);
puts(s);

free(s);
s = NULL;

return 0;

能够运行!
程序二:
#include<stdio.h>
#include<stdlib.h>

int main()

char *s;

s = (char *)malloc(sizeof(char));

gets(s);
puts(s);

free(s);
s = NULL;

return 0;

不能运行!

程序三:
#include<stdio.h>
#include<stdlib.h>

int main()

char *s;
s = (char *)malloc( sizeof(char));
gets(s);
puts(s);
return 0;

可以运行!

程序四:
#include<stdio.h>
#include<string.h>
int main()

char s[20]="djksafd";
char *str=s;
char s1[2];
strcpy(s1,str);
printf("%s\n",s1);
return 0;

不能运行!

程序五:
#include<stdio.h>
#include<string.h>
int main()

char s[20]="djksafd";
char *str="hakdshkdsak";
char s1[2];
strcpy(s1,str);
printf("%s\n",s1);
return 0;

可以运行!

程序六:
#include<stdio.h>
#include<string.h>
int main()

char s[20]="djksafd";
char *str=s;
char s1[2];
strcpy(s1,str);
printf("%s\n",str);
return 0;


不能运行!

这是怎么回事?请专家解答!
程序七:
#include<stdio.h>
#include<string.h>
int main()

char s[20]="djksafd";
char *str=s;
char s1[20];
strcpy(s1,str);
printf("%s\n",s1);
return 0;

可以运行!

参考技术A 楼上的回答都很高深,没看明白。把我的理解也说下:
C语言中的字符串(C++中叫做C风格字符串),他的一个最大特点就是以NULL结尾。所以他的存储空间比实际字符数多一个。
C风格字符串,在C中是标准库类型,不是C的内置类型。他的内存管理由程序负责。
内存管理不好会产生溢出。
malloc和free是C语言中用来管理内存(或者叫堆)的。
free释放内存空间。如果不释放会产生内存(堆)耗尽。
字符数组复制给字符数组,会产生溢出(数组对存储空间大小有要求)。
C语言中的字符指针在内存中是线性存储的,他将一块连续的区域(直到出现NULL为止)做为一个字符串。没有存储空间大小的要求。 字符数组复制给字符指针,或字符指针复制给字符指针。不会产生溢出。
动态创建的数组(返回指向新分配数组第一个元素的指针,可见本质是一个指针。),当释放时会报错(释放时释放的是空间,当然有存储空间大小要求)。
4、char s[20]="djksafd";
char *str=s;//对str进行解引用后是数组s。
5、char s[20]="djksafd";
char *str="hakdshkdsak";//对str解引用后是C风格字符串追问

还是没说到点子上,哎!

参考技术B 除程序1外,其余的本质上讲都是有问题的,不管他可不可以通过编译,可不可以“运行”

程序1没什么好解释的,唯一要注意的是不要输入超过100个字符

程序2和3,分配的字节数过小,而程序3之所以看似能“运行”是因为他没有free函数,但是当输入的字符比较多时,比如说多于二三十个字符时,你就会显示的看到,系统报错

程序4,不用运行,根本就是逻辑上有问题
char s1[2];
strcpy(s1,str);
最基本的strcpy函数的第一个参数,是一个指向足够大空间的指针,以容纳第二个参数指向的内容,这个就根本不满足

程序5同2,3的道理,把字符数一加多,就会有问题

程序6和4完全是一个东西

总之,lz都是在运用C编译器不对越界进行检查的特性乱来而已,本质上都是不可行的,且不具有可移植性,如果采用对越界进行较为严格检查的编译器,立马会报错,比如VS2010

最后给个忠告,不要没事做这种无意义的实验追问

你说的我都知道!!!我想知道根本原因!

追答

MSDN上关于malloc的部分有以下注意点

Remarks

The malloc function allocates a memory block of at least size bytes. The block may be larger than size bytes because of space required for alignment and maintenance information.

也就是说malloc,由于内存对齐和存储维护信息的关系,实际申请的内存空间数可能是大于申请时的size数量的,但是无论如何也绝不应该越界

同时这也正是为什么程序2中会在free的位置上报错的原因,显然由于越界的关系,malloc的相关信息被覆盖了,导致free出现的问题

如果还要再深究的,那就要讲到malloc的实现,以及不同操作系统对于内存管理机制的原理与实现上来了

我承认讲这个的话,就远超我的能力范围了,你要找大神级别的人去问了

本回答被提问者和网友采纳
参考技术C 对于程序2
malloc分配内存的时候,这片内存的结尾会有个标记,因为他只分配了一个字符的空间,也就是一个字节,所以他在输入一个字符的时候,实际上有两个字符,还有个回车,回车把这片内存的结束标记给占据了,所以释放的时候不能判别了,所以就报内存错误了。如果直接回车就不会有事了。
程序4和程序6不是一样的吗,不过我这边怎么没事,没有错啊追问

大哥注意看问题补充!因为网速不好,搞的我基本把所有程序都复制了2遍才粘贴,所以才会这样,sorry!

参考技术D 前几个程序没发现什么问题,不知道你用的是什么环境,我帮你运行了下,上面所有你说不能运行的程序都是可以被编译(我用的是DEV C++),你可以去试试。。。
你最后一个程序char *str=s这样赋值是不行的,很容易出错,你可以改下
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()

char s[20]="djksafd";
char *str;
char s1[20];
str=(char*)malloc(sizeof(char));
strcpy(str,s);
strcpy(s1,str);
printf("%s\n",str);
getchar();
return 0;
追问

这些程序都是我的试验品,是我刻意这样编的,目的是搞清楚其局限性,这样才能更好地运用这些库函数!另外,能编译并不代表正确,否则我也不会多此一问了。这个问题恐怕不是单靠基本的C语言就能解决的,可能涉及到汇编原理和储存原理!

第5个回答  2012-04-03 不能运行的都是因为内存访问越界了,使用字符指针操作字符串的时候一定要确保你的指针指向的空间足够放下字符串。追问

既不仔细看程序,也没用VC6.0运行,就回答!打酱油也不能这样啊!!!

用JS获取地址栏参数的方法(超级简单)

方法一:采用正则表达式获取地址栏参数:( 强烈推荐,既实用又方便!)

function GetQueryString(name)
{
     var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
     var r = window.location.search.substr(1).match(reg);
     if(r!=null)return  unescape(r[2]); return null;
}
 
// 调用方法
alert(GetQueryString("参数名1"));
alert(GetQueryString("参数名2"));
alert(GetQueryString("参数名3"));

下面举一个例子:

若地址栏URL为:abc.html?id=123&url=http://www.maidq.com

那么,但你用上面的方法去调用:alert(GetQueryString("url"));

则会弹出一个对话框:内容就是 http://www.maidq.com

如果用:alert(GetQueryString("id"));那么弹出的内容就是 123 啦;

当然如果你没有传参数的话,比如你的地址是 abc.html 后面没有参数,那强行输出调用结果有的时候会报错:

所以我们要加一个判断 ,判断我们请求的参数是否为空,首先把值赋给一个变量:

var myurl=GetQueryString("url");
if(myurl !=null && myurl.toString().length>1)
{
   alert(GetQueryString("url"));
}

这样就不会报错了!

方法二:传统方法

<script type="text/javascript">
function UrlSearch() 
{
   var name,value; 
   var str=location.href; //取得整个地址栏
   var num=str.indexOf("?") 
   str=str.substr(num+1); //取得所有参数   stringvar.substr(start [, length ]

   var arr=str.split("&"); //各个参数放到数组里
   for(var i=0;i < arr.length;i++){ 
    num=arr[i].indexOf("="); 
    if(num>0){ 
     name=arr[i].substring(0,num);
     value=arr[i].substr(num+1);
     this[name]=value;
     } 
    } 

var Request=new UrlSearch(); //实例化
alert(Request.id);
</script>

比如说把这个代码存为1.html

那么我要访问1.html?id=test

这个时候就取到test的值了


在html里调用
<script type="text/javascript">
var a="http://baidu.com";
</script>
</head>
<body>
<a id="a1" href="">sadfsdfas</a>
<script>
var a1=document.getElementById("a1");
a1.href=a;
</script>

<script type="text/javascript"> 
var a="http://xxx.com/gg.htm?cctv"; 
var s=a.indexOf("?"); 
var t=a.substring(s+1);// t就是?后面的东西了 

</script>

stringvar.substr(start [, length ]

返回一个从指定位置开始的指定长度的子字符串。

stringvar

必选项。要提取子字符串的字符串文字或 String 对象。

start

必选项。所需的子字符串的起始位置。字符串中的第一个字符的索引为 0。

length

可选项。在返回的子字符串中应包括的字符个数。

如果 length 为 0 或负数,将返回一个空字符串。如果没有指定该参数,则子字符串将延续到 stringvar 的最后。

下面列举出一些相关的参数:

str.toLowerCase()   转换成小写  
str.toUpperCase()   字符串全部转换成大写

URL即:统一资源定位符 (Uniform Resource Locator, URL) 
完整的URL由这几个部分构成:
scheme://host:port/path?query#fragment 
scheme:通信协议
常用的http,ftp,maito等

host:主机
服务器(计算机)域名系统 (DNS) 主机名或 IP 地址。

port:端口号
整数,可选,省略时使用方案的默认端口,如http的默认端口为80。

path:路径
由零或多个"/"符号隔开的字符串,一般用来表示主机上的一个目录或文件地址。

query:查询
可选,用于给动态网页(如使用CGI、ISAPI、PHP/JSP/ASP/ASP.NET等技术制作的网页)传递参数,可有多个参数,用"&"符号隔开,每个参数的名和值用"="符号隔开。

fragment:信息片断
字符串,用于指定网络资源中的片断。例如一个网页中有多个名词解释,可使用fragment直接定位到某一名词解释。(也称为锚点.)

对于这样一个URL

http://www.maidq.com/index.html?ver=1.0&id=6#imhere

我们可以用javascript获得其中的各个部分
1, window.location.href
整个URl字符串(在浏览器中就是完整的地址栏)
本例返回值: http://www.maidq.com/index.html?ver=1.0&id=6#imhere

2,window.location.protocol
URL 的协议部分
本例返回值:http:

3,window.location.host
URL 的主机部分
本例返回值:www.maidq.com

4,window.location.port
URL 的端口部分
如果采用默认的80端口(update:即使添加了:80),那么返回值并不是默认的80而是空字符
本例返回值:""

5,window.location.pathname
URL 的路径部分(就是文件地址)
本例返回值:/fisker/post/0703/window.location.html

6,window.location.search
查询(参数)部分
除了给动态语言赋值以外,我们同样可以给静态页面,并使用javascript来获得相信应的参数值
本例返回值:?ver=1.0&id=6

7,window.location.hash
锚点
本例返回值:#imhere

以上是关于一个既超级简单又超级复杂的C语言问题:的主要内容,如果未能解决你的问题,请参考以下文章

C语言学习笔记超级炫酷的C语言实用小技巧,学会这些隐藏技巧,早下班一小时

分享几个超级实用的C语言小技巧!

分享几个超级实用的C语言小技巧!

超级简单C语言请详细解释黄色字体 Succs[snum++]=i 不明白sum++是啥意思,后面

2020牛客寒假算法基础集训营5.C——C语言IDE超级大模拟

C语言 打地鼠游戏 超级详解,各个函数与算法,设计思路与流程。