GDB调试字符数组时指针和数组区别的体现
测试ftell函数时发现报错,先贴源码
// File Name: ftell.c
#include <stdio.h>
#include <stdlib.h> int main(int argc, char** argv)
{
FILE* fp = fopen("myfile.in", "r");
if (fp == NULL) {
perror("fopen error");
exit(1);
}
char buf[4];
fgets(buf, 4, fp);
if (fputs(buf, fp) == EOF) {
perror("fputs error");
exit(1);
}
if (ferror(fp)) {
perror("ferror");
exit(1);
} return 0;
}
错误信息如下

于是用GDB调试,在fputs处设断点,输出字符数组

突然我想查看每个字符的值,于是看到的是这个

啊,突然想起来,buf的类型并不是char*,虽然如果作为函数输入参数的话会被当成char*,但是buf的实际类型是char (*)[4]
所以输出的是4个char (*)[4],也就是buf开始的16个字符
但是我使用p &buf[0]@sizeof(buf)会报错Only values in memory can be extended with '@'
想着可能需要类型转换,加了(char*)后还是报错,原来是因为只有值才能狗用@扩展,GDB会取得值的指针,然后用@往前移动
于是几个调试如下
(gdb) p buf
$1 = "lin"
(gdb) p &buf[0]
$2 = 0x7fffffffde90 "lin"
(gdb) p &buf[0]@4
Only values in memory can be extended with '@'.
(gdb) p (char*)&buf[0]@4
Only values in memory can be extended with '@'.
(gdb) p *(char*)&buf[0]@4
$3 = "lin"
(gdb) p *buf@4
$4 = "lin"
\0是看不到的,除非单独查看那一位的字符
(gdb) p (int)buf[3]
$5 = 0
(gdb) p buf[3]
$6 = 0 '\000'
OK,继续解决fputs出错的问题吧。
其实perror显示的信息很完美了,错误原因是Bad file descriptor,在这里文件描述符藏在FILE*指向的对象里,错误也就是fp。
这里我是要把信息输出到屏幕上,所以fputs的第二个输入参数应该是标准输出stdout,而不是我打开的文件指针fp。
由于fopen选择了读取模式,所以无法进行写入。
试着把fopen第二个参数改成"r+",允许写入,结果如下

该文本之前第1行是line 01,现在被改成了linlin1,因为读取3个字符时偏移量是3(即'e'所在位置),然后又写入了3个字符,所以"lin"替代的是"e 0"。
这里也可以发现,用"r"而不是"r+"来禁止写入能够检查出一些容易忽视的错误。
修改后如下
// File Name: ftell.c
#include <stdio.h>
#include <stdlib.h> int main(int argc, char** argv)
{
FILE* fp = fopen("myfile.in", "r");
if (fp == NULL) {
perror("fopen error");
exit(1);
}
char buf[4];
fgets(buf, 4, fp);
if (fputs(buf, stdout) == EOF) {
perror("fputs error");
exit(1);
}
printf("\nfile offset: %ld\n", ftell(fp));
if (ferror(fp)) {
perror("ferror");
exit(1);
} fclose(fp); return 0;
}
/* output:
lin
file offset: 3
*/
GDB调试字符数组时指针和数组区别的体现的更多相关文章
- [C++]指针和指向数组的指针[一维数组与指针]
1.一维数组与指针 形如:int型 数组 a[10] 1)&a[0] 地址常量;地址类型:int *型 ; 存储数组a的首地址 ...
- C/C++拾遗(一):关于数组的指针和数组元素首地址的一道经典题
代码例如以下: #include <stdio.h> int main(void) { int a[5] = {1, 2, 3, 4, 5}; int *ptr = (int *)(&am ...
- Vscode 调试 C 语言时数组值无法显示的问题
使用 Vscode 的 Gdb 扩展调试 C 语言时,发现数组变量在 变量列表里面中显示为指针,且只显示为其第一个元素的值,无法看到所有元素的值. 如图所示: 解决: 假设有一个元素个数为10的数组v ...
- gdb 调试(查看运行时数据) 四
在使用GDB调试程序时,触发断点后,可以使用print命令(简写为p),或是同义命令inspect来查看当前程序的运行数据.print命令的格式是: print <expr> pri ...
- C++数组和指针
<C++ Primer 4th>读书摘要 与 vector 类型相似,数组也可以保存某种类型的一组对象:而它们的区别在于,数组的长度是固定的.数组一经创建,就不允许添加新的元素.指针则可以 ...
- C/C++中数组与指针的关系探究
数组与指针 长期以来,在C/C++中,数组名和指向数组首元素的指针常量到底是以一种什么关系,一直困扰着很多人.很多地方,甚至是一些教科书中都在说,"数组名就是一个指向数组首元素的指针常量&q ...
- C Primer Plus学习笔记(九)- 数组和指针
数组 数组由数据类型相同的同一系列元素组成 需要使用数组时,通过声明数组告诉编译器数组中内含多少元素和这些元素的类型 普通变量可以使用的类型,数组元素都可以用 float candy[365]; // ...
- C中 数组和指针的异同
数组在很多情况下是和指针等价的,数组的下标运算和指针的解引用也有等价形式:arr[i] == *(arr + 1):但是也有一些情况下数组和指针是不一样的:extern int arr[]; exte ...
- C++数组(指针)作为函数参数
本文的学习内容参考:http://blog.csdn.net/wwdlk/article/details/6322843 1.当用数组名作为函数参数时,函数的实参和形参都应为数组名(或者指针): Ex ...
随机推荐
- Mutations
蛤蟆可以吃队友,也可以吃对手. 如果数组第一个字符串元素包含了第二个字符串元素的所有字符,函数返回true. 举例,["hello", "Hello"]应该返回 ...
- 006PHP基础知识——数据类型(三)
<?php /** * 数据类型(三) * PHP是一个弱类型的语言 */ //检测数据类型:gettype() 返回字符串的数据类型 /*$str="美丽中国"; echo ...
- 十二、dbms_logmnr(分析重做日志和归档日志)
1.概述 作用:通过使用包DBMS_LOGMNR和DBMS_LOGMNR_D,可以分析重做日志和归档日志所记载的事务变化,最终确定误操作(例如DROP TABLE)的时间,跟踪用户事务操作,跟踪并还原 ...
- LA3029
题解: 一个类似尺取法的算法 代码: #include<cstdio> #include<algorithm> using namespace std; ; int T,n,m ...
- fegin 调用源码分析
http://techblog.ppdai.com/2018/05/28/20180528/ 这篇文章是相当详细
- 链表实现队列C语言写法
#include<iostream> #include<cstdio> #include<cstdlib> using namespace std; typedef ...
- NODE 开发 2-3年工作经验 掌握的相关知识
文章 部分答案 内存
- Linux:运行级别,root密码重置,救援模式,安装图形化界面
运行级别,root密码重置,救援模式,安装图形界面 运行级别 1.查看当前系统的运行级别 runlevel 2.认识各个运行级别以及开机自启运行级别 Linux系统运行级别共7个执行 vi /etc/ ...
- 如何将dom4j的jar包放到java项目中
---恢复内容开始--- 如果你建的是java project项目的话,那就通过Myeclispe中的右键你的项目名称,选择build path ->config build path... 然 ...
- onunload、onbeforeunload事件详解--zhuan
最近项目中做到一个功能:在上传页面用户开始上传文件之后用户点击任意跳转都需要弹出提示层进行二次确定才允许他进行跳转,这样做的目的是为了防止用户的错误操作导致这珍贵的UGC 流失(通常用户在一次上传不成 ...