草庐IT

关于堆栈:简单的 C 代码错误

codeneng 2023-03-28 原文

Simple C Code Error

有谁知道为什么我在运行这段代码时会出现段错误? Valgrind 告诉我,我在第 13 行 if( !isdigit(x) ) 上有"大小为 4 的未初始化值",并且在同一行上有一个无效的读取大小 2 - 地址不是堆栈\\'d,malloc\\'d ,或免费的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdbool.h>

int main()
{
    int x;

    printf("Please enter a number:");
    scanf("%d", &x);

    if( !isdigit(x) )
    {
        printf("You entered %d\
"
, x);
    }
    else
    {
        printf("You did not enter a valid number!\
"
);
    }

    return 0;
}

  • isdigit 用于处理字符值;例如,对于 '1' 的输入,它将返回 true,对于 'a' 的输入,它将返回 false。你要输入什么?
  • 如果您使用 %d,则 isdigit() 不会以您希望的方式工作。例如,如果输入 1x 将不包含字符 1 的 ASCII 码,因此 isdigit() 将返回 false。
  • 请记住始终检查输入是否成功:scanf(...) == 1
  • 不相关,但如果输入不是数字,scanf 将失败。因此,您可以将其替换为 scanf 的结果,而不是检查 "isdigit"。
  • "得到一个段错误" - 这不是一个段错误。


我用 g 编译了你的代码,导致没有段错误。

输入值:

5、-1、27、43545gbb 和 gggg

产生的结果:

5、-1、27、43545 和 1729208414

  • 您的输入会导致未定义的行为。您没有遵守 isdigit 的先决条件。更不用说从最后的输出中可以清楚地看出您正在使用未初始化的变量。简而言之,虽然这对您(现在)没有段错误,但它可以在任何时候。


我认为问题在于如果 scanf 失败,x 将未初始化。
最好在字符数组中输入数据。否则,您的代码没有意义,因为您无法在 int 类型的对象中输入非数字。此外,如果您输入一个数字,使用函数 isdigit 的结果可能会出乎意料。

  • 我不认为是解决方案。例如,如果你用零值初始化 x,然后输入"dkj",输出将是你输入了 0。这不是他想要的。当然,使用默认值初始化变量始终是一个好习惯。谢谢。


尝试以下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int x = 0;
    char a;

    printf("Please enter a number:");

    while(scanf("%d%c",&x,&a) != 2 || a != '\
'
)
    {
        printf("Please enter an integer only :");
        do
        {
            scanf("%c",&a);
        }while(a != '\
'
);
    }

    printf("You entered %d\
"
, x);
    return 0;
}

代码向您展示了如何使用 scanf 的复杂方法。有关更多信息:scanf 的工作并检查输入是否为 int

根据 c 文档:isdigit

原型:

1
int isdigit( int ch );

参数:

1
ch  -   character to classify

目的:

Checks if the given character is a numeric character (0123456789).
The behavior is undefined if the value of ch is not representable as unsigned char and is not equal to EOF.

返回值:

Non-zero value (true) if the character is a numeric character, 0 (false) otherwise.


为什么第 13 行出现问题?第 13 行是 if( !isdigit(x) )
在第 8 行创建 x 时,您没有初始化它,
因此,如果输入了一个不可接受的值,并在第 11 行由 scanf() 处理,则它将在到达 isdigit() 函数时继续未初始化。

问题在于 isdigit() 期望输入必须是整数值介于 0 和 255 之间的字符。任何其他值都会导致未定义的行为。段错误是未定义行为的可能结果之一。

还有其他方法可以实现这一点,例如:
这是一个使用 char 数组(字符串)的示例。请注意注释以解释为什么要完成某些事情。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int main()
{
    //int x;
    char x[2];  //Good for only one digit

    printf("Please enter an integer with up to 10 digits:");
    //scanf("%d", &x);
    scanf("%1s", x); //Edited to allow maximum field width of 1.

   // if( !isdigit(x) )        
    if( isdigit(x[0]) ) //note the"!" was removed for logic to work
    {
        printf("You entered %d\
"
, atoi(x)); //note use of atoi() to convert string to int.
    }
    else
    {
        printf("You did not enter a valid number!\
"
);
    }

    return 0;
}

  • isdigit 采用 int。只是你给它的 int 必须在 unsigned charEOF 的范围内。
  • 当您可以检查 if scanf(%d)==1 时,为什么要读取字符串并进行转换?
  • @prajmus - 是的, scanf() 会工作。但是一个字符数组也是如此。由于 isdigit() 是一个字符测试器,我认为最好以 char 类型为例来说明使用该函数。此外,这里的核心问题是为什么会出现段错误?这可以通过解决作??为参数传递给 isdigit 的非法值来解决。
  • char x[2]; scanf("%s", x); - 没有。
  • @MattMcNabb - 使用扩展缓冲区进行编辑。让我知道这是否不是问题所在。谢谢。
  • @ryyker 并没有更好,它仍然有缓冲区溢出。在 scanf 中使用最大字段宽度修饰符。
  • @MattMcNabb - 已编辑,谢谢。仍在学习 scanf() 格式说明符的变体。感谢帮助。

有关关于堆栈:简单的 C 代码错误的更多相关文章

  1. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  2. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  3. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  4. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

    我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

  5. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  6. ruby - 简单获取法拉第超时 - 2

    有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url

  7. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  8. ruby-on-rails - 错误 : Error installing pg: ERROR: Failed to build gem native extension - 2

    我克隆了一个rails仓库,我现在正尝试捆绑安装背景:OSXElCapitanruby2.2.3p173(2015-08-18修订版51636)[x86_64-darwin15]rails-v在您的Gemfile中列出的或native可用的任何gem源中找不到gem'pg(>=0)ruby​​'。运行bundleinstall以安装缺少的gem。bundleinstallFetchinggemmetadatafromhttps://rubygems.org/............Fetchingversionmetadatafromhttps://rubygems.org/...Fe

  9. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

  10. ruby-on-rails - 每次我尝试部署时,我都会得到 - (gcloud.preview.app.deploy) 错误响应 : [4] DEADLINE_EXCEEDED - 2

    我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie

随机推荐