📄 linux 下 c 语言编程1.html
字号:
void my_print (char *string)
{
printf ("The string is %s\n", string);
}
void my_print2 (char *string)
{
char *string2;
int size, i;
size = strlen (string);
string2 = (char *) malloc (size + 1);
for (i = 0; i < size; i++)
string2[size - i] = string[i];
string2[size+1] = `\0';
printf ("The string printed backward is %s\n", string2);
}</font></pre>
用下面的命令编译它:
<br>
<pre><font color="#0066ff">gcc -o test test.c</font></pre>
这个程序执行时显示如下结果:
<pre><font color="#0066ff">The string is hello there
The string printed backward is</font></pre>
输出的第一行是正确的, 但第二行打印出的东西并不是我们所期望的.
我们所设想的输出应该是:
<pre><font color="#0066ff">The string printed backward is ereht olleh</font></pre>
由于某些原因, <tt>my_print2</tt> 函数没有正常工作. 让我们用
<tt>gdb</tt> 看看问题究竟出在哪儿, 先键入如下命令:
<br>
<pre><font color="#0066ff">gdb greeting</font></pre>
<dl>
<dd>
<hr width="90%"><b>注意:</b> 记得在编译 <tt>greeting</tt> 程序时把调试选项打开.
<hr width="90%"></dd>
</dl>
如果你在输入命令时忘了把要调试的程序作为参数传给 <tt>gdb</tt>
, 你可以在 <tt>gdb</tt> 提示符下用 file 命令来载入它:
<br>
<pre><font color="#0066ff">(gdb) file greeting</font></pre>
这个命令将载入 <tt>greeting</tt> 可执行文件就象你在
<tt>gdb</tt> 命令行里装入它一样.
<p> 这时你能用 <tt>gdb</tt> 的 run 命令来运行 <tt>greeting</tt>
了. 当它在 <tt>gdb</tt> 里被运行后结果大约会象这样:
</p><pre><font color="#0066ff">(gdb) run
Starting program: /root/greeting
The string is hello there
The string printed backward is
Program exited with code 041</font></pre>
这个输出和在 <tt>gdb</tt> 外面运行的结果一样. 问题是,
为什么反序打印没有工作? 为了找出症结所在, 我们可以在 <tt>my_print2</tt>
函数的 <tt>for</tt> 语句后设一个断点, 具体的做法是在 <tt>gdb</tt> 提示符下键入
<tt>list</tt> 命令三次, 列出源代码:
<pre><font color="#0066ff">(gdb) list
(gdb) list
(gdb) list</font></pre>
<dl>
<dd>
<hr width="90%"><b>技巧:</b> 在 <tt>gdb</tt> 提示符下按回车健将重复上一个命令.
<hr width="90%"></dd>
</dl>
第一次键入 <tt>list</tt> 命令的输出如下:
<br>
<pre><font color="#0066ff">1 #include <stdio.h>
2
3 main ()
4 {
5 char my_string[] = "hello there";
6
7 my_print (my_string);
8 my_print2 (my_string);
9 }
10</font></pre>
如果按下回车, <tt>gdb</tt> 将再执行一次 <tt>list</tt>
命令, 给出下列输出:
<br>
<pre><font color="#0066ff">11 my_print (char *string)
12 {
13 printf ("The string is %s\n", string);
14 }
15
16 my_print2 (char *string)
17 {
18 char *string2;
19 int size, i;
20</font></pre>
再按一次回车将列出 <tt>greeting</tt> 程序的剩余部分:
<pre><font color="#0066ff">21 size = strlen (string);
22 string2 = (char *) malloc (size + 1);
23 for (i = 0; i < size; i++)
24 string2[size - i] = string[i];
25 string2[size+1] = `\0';
26 printf ("The string printed backward is %s\n", string2);
27 }</font></pre>
根据列出的源程序, 你能看到要设断点的地方在第24行, 在
<tt>gdb</tt> 命令行提示符下键入如下命令设置断点:
<pre><font color="#0066ff">(gdb) break 24</font></pre>
<tt> gdb</tt> 将作出如下的响应:
<pre><font color="#0066ff">Breakpoint 1 at 0x139: file greeting.c, line 24
(gdb)</font></pre>
<br> 现在再键入 <tt>run </tt>命令, 将产生如下的输出:
<br>
<pre><font color="#0066ff">Starting program: /root/greeting
The string is hello there
Breakpoint 1, my_print2 (string = 0xbfffdc4 "hello there") at greeting.c :24
24 string2[size-i]=string[i]</font></pre>
你能通过设置一个观察 <tt>string2[size - i]</tt> 变量的值的观察点来看出错误是怎样产生的,
做法是键入:
<br>
<pre><font color="#0066ff">(gdb) watch string2[size - i]</font></pre>
<tt> gdb</tt> 将作出如下回应:
<pre><font color="#0066ff">Watchpoint 2: string2[size - i]</font></pre>
现在可以用 <tt>next</tt> 命令来一步步的执行 <tt>for</tt>
循环了:
<br>
<pre><font color="#0066ff">(gdb) next</font></pre>
经过第一次循环后, <tt>gdb</tt> 告诉我们 <tt>string2[size
- i]</tt> 的值是 <tt>`h`.</tt> <tt>gdb</tt> 用如下的显示来告诉你这个信息:
<br>
<pre><font color="#0066ff">Watchpoint 2, string2[size - i]
Old value = 0 `\000'
New value = 104 `h'
my_print2(string = 0xbfffdc4 "hello there") at greeting.c:23
23 for (i=0; i<size; i++)</font></pre>
这个值正是期望的. 后来的数次循环的结果都是正确的. 当
<tt>i=10 </tt>时, 表达式 <tt>string2[size - i]</tt> 的值等于 <tt>`e`</tt>,
<tt>size - i</tt> 的值等于 1, 最后一个字符已经拷到新串里了.
<p> 如果你再把循环执行下去, 你会看到已经没有值分配给
<tt>string2[0] </tt>了,<tt> </tt> 而它是新串的第一个字符, 因为 <tt>malloc</tt>
函数在分配内存时把它们初始化为空(null)字符. 所以 <tt>string2</tt> 的第一个字符是空字符.
这解释了为什么在打印 <tt>string2</tt> 时没有任何输出了.
</p><p> 现在找出了问题出在哪里, 修正这个错误是很容易的. 你得把代码里写入
<tt>string2</tt> 的第一个字符的的偏移量改为 <tt>size - 1</tt> 而不是 <tt>size</tt>.
这是因为 <tt>string2</tt> 的大小为 12, 但起始偏移量是 0, 串内的字符从偏移量
0 到 偏移量 10, 偏移量 11 为空字符保留.
</p><p> 为了使代码正常工作有很多种修改办法. 一种是另设一个比串的实际大小小
1 的变量. 这是这种解决办法的代码:
</p><pre><font color="#0066ff">#include <stdio.h>
main ()
{
char my_string[] = "hello there";
my_print (my_string);
my_print2 (my_string);
}
my_print (char *string)
{
printf ("The string is %s\n", string);
}
my_print2 (char *string)
{
char *string2;
int size, size2, i;
size = strlen (string);
size2 = size -1;
string2 = (char *) malloc (size + 1);
for (i = 0; i < size; i++)
string2[size2 - i] = string[i];
string2[size] = `\0';
printf ("The string printed backward is %s\n", string2);
}</font></pre>
<h3>
<font color="#ff9900">
另外的 C 编程工具</font></h3>
Slackware Linux 的发行版中还包括一些我们尚未提到的 C
开发工具. 本节将介绍这些工具和它们的典型用法.
<h4>
xxgdb</h4>
<tt> xxgdb</tt> 是 <tt>gdb</tt> 的一个基于 X Window 系统的图形界面.
<tt>xxgdb </tt>包括了命令行版的 <tt>gdb</tt> 上的所有特性. <tt>xxgdb
</tt>使你能通过按按钮来执行常用的命令. 设置了断点的地方也用图形来显示.
<br>
<br> 你能在一个 <tt>Xterm</tt> 窗口里键入下面的命令来运行它:
<pre><font color="#0066ff">xxgdb</font></pre>
你能用 <tt>gdb</tt> 里任何有效的命令行选项来初始化 <tt>xxgdb</tt>
. 此外 <tt>xxgdb</tt> 也有一些特有的命令行选项, 表 27.2 列出了这些选项.
<br> <b><font size="+1">表 27.2. xxgdb 命令行选项.</font></b>
<table border="1">
<tbody><tr rowspan="1" align="left">
<td align="left" width="70"><i>选 项</i></td>
<td align="left"><i>描 述</i></td>
</tr>
<tr rowspan="1" align="left">
<td align="left" width="70"><tt>db_name</tt></td>
<td align="left">指定所用调试器的名字, 缺省是 <tt>gdb</tt>.</td>
</tr>
<tr rowspan="1" align="left">
<td align="left" width="70"><tt>db_prompt</tt></td>
<td align="left">指定调试器提示符, 缺省为 <tt>gdb</tt>.</td>
</tr>
<tr rowspan="1" align="left">
<td align="left" width="70"><tt>gdbinit</tt></td>
<td align="left">
指定初始化 <tt>gdb</tt> 的命令文件的文件名, 缺省为 <tt>.gdbinit</tt>.
</td>
</tr>
<tr rowspan="1" align="left">
<td align="left" width="70"><tt>nx</tt></td>
<td align="left">告诉 <tt>xxgdb</tt> 不执行 <tt>.gdbinit</tt> 文件.</td>
</tr>
<tr rowspan="1" align="left">
<td align="left" width="70"><tt>bigicon</tt></td>
<td align="left">使用大图标.</td>
</tr>
</tbody></table>
<br>
<br>
<h4>
calls</h4>
<tt> </tt>你可以在 <tt>sunsite.unc.edu</tt> FTP
站点用下面的路径:
<p><tt><font color="#3366ff">/pub/Linux/devel/lang/c/calls.tar.Z</font></tt>
</p><p> 来取得 <tt>calls , </tt>一些旧版本的 Linux CD-ROM
发行版里也附带有. 因为它是一个有用的工具, 我们在这里也介绍一下. 如果你觉得有用的话,
从 BBS, FTP, 或另一张CD-ROM 上弄一个拷贝. <tt>calls</tt> 调用 GCC
的预处理器来处理给出的源程序文件, 然后输出这些文件的里的函数调用树图.
<br>
</p><dl>
<dd>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -