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 *[email protected]
$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
*/

  

时间: 2024-08-07 00:17:40

GDB调试字符数组时指针和数组区别的体现的相关文章

数组的初始化和二维数组、指针与数组

1.数组的初始化,比较简单,实例程如下: #include<stdio.h> # define M 12 int main(void){ int days[M]={31,28,31,30,31,30,31,30,30,31,30,31}; int i; for(i=0;i<M;i++) printf("Months %d has %2d days.\n",i+1,days[i]); return 0; } 运行结果如下: 2.未经初始化的数组: 实例程序: #incl

什么是指针?什么是数组?指针和数组的关系?

形象地讲,我们可以把计算机的内存看作一条长街上的一排房屋,每个房间都可以容纳数据并通过一个房号来表识.而表示每个房间房号的值我们可以称为地址.或许这样的比喻有局限性,毕竟真实地计算机内存是以数以万计的bit位组成. ⑴初始化: ①最简单的以 int *p 为例,初始化时内存里开辟了四个字节的空间. ▇▇▇▇ ②另一个声明 ,现在,我们有两个变量,下图中显示了后面那个未知内容的内存. char ch = 'a': char cp = &a; ▇→▇▓←(?) (cp)      (ch) ⑵&quo

C/C++拾遗(一):关于数组的指针和数组元素首地址的一道经典题

代码如下: #include <stdio.h> int main(void) { int a[5] = {1, 2, 3, 4, 5}; int *ptr = (int *)(&a+1); int *p1 = a; int *p2 = &a[0]; int *p3 = (int *)(&a); if(p1 == p2){ printf("p1 == p2\n"); }else{ printf("p1 != p2\n"); } i

使用gdb调试C++程序时,感觉不按流程执行,跳来跳去的解决办法

在使用gdb进行调试的时候,依赖于g++的编译结果,因为在编译时默认使用了优化,所以导致没按代码顺序执行,其实只需要将g++的编译优化关掉就可以了. gdb调试程序的时候打印变量值会出现<value optimized out> 情况,可以在gcc编译的时候加上 -O0参数项,意思是不进行编译优化,调试的时候就会顺畅了,运行流程不会跳来跳去的,发布项目的时候记得不要在使用 -O0参数项,gcc 默认编译或加上-O2优化编译会提高程序运行速度.

指针和数组,字符和字符串等易混淆概念举例

指针和数组相关概念 文档不知道从哪搞的,基础知识,觉得有用的可以看看,留存. 有侵权的内容,请及时告知,谢谢! 指针和数组相关概念 ************************************************* 字符与字符串的区别:单引号字符其实就是代表ASCII码的整数,而字符串代表了无名数组起始的指针 指针与数组1:任何一个数组下标运算都等同于一个对应的指针运算:对数组只能知道数组的大小,和获得指向下标为0的指针,intcalendar[12][31];sizeof(ca

C++primer第四章 数组和指针

4.1. 数组 数组是由类型名.标识符和维数组成的复合数据类型(第 2.5 节),类型名规定了存放在数组中的元素的类型,而维数则指定数组中包含的元素个数. 数组定义中的类型名可以是内置数据类型或类类型:除引用之外,数组元素的类型还可以是任意的复合类型.没有所有元素都是引用的数组. 4.1.1. 数组的定义和初始化 数组的维数必须用值大于等于 1 的常量表达式定义(第 2.7 节). 此常量表达式只能包含整型字面值常量.枚举常量(第 2.7 节)或者用常量表达式初始化的整型 const 对象. /

C语言--&gt;(十一)指针于数组

知识点: • 指针与变量 (指向变量的指针)• 指针与函数 (地址传递) • 指针与数组 (指向数组的指针) • 指针与字符串 =================================数组的指针 1.什么是数组指针 1)数组的指针是指数组在内存的的起始位置 2)数组的第一个元素和数组的起始地址一致 2.数组名的本质 1)数组名本质上是一个地址常量,代表的是数组的首地址也就是第一个元素的地址 数组名表示表示数组的起始地址,不表示整个数组,不能对数组整体赋值. 3.数组名为一个指针常量,可

附录一 再论指针和数组

附录一 附录一 再论指针和数组 再论指针和数组 [email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git 预习检查 链表单元有哪几个部分组成 如何申请链表单元,及释放链表单元 实现单链表插入的基本语法 简述一下快速排序基本理论要点 [email protected]:Kevin-Dfg/[email protected]:Kevin-Dfg/Dat

C++ Primer 第四版读书笔记(三)之数组与指针

C++语言提供了两种类似于vector和迭代器类型的低级复合类型--数组与指针.与vector类型相似,数组也可以保存某种类型的一组对象:而它们的区别在于,数组的长度是固定的.数组一经创建,就不允许添加新的元素.指针则可以像迭代器一样用于遍历和检查数组中的元素. 现代C++程序应尽量使用vector和迭代器类型,而避免使用低级的数组和指针.设计良好的程序只有在强调速度时才在类实现的内部使用数组和指针. 数组是C++语言中类似于标准库vector类型的内置数据结构.与vector类似,数组也是一种