为什么printf()会出现运行时错误?

时间:2017-03-04 20:02:13

标签: c printf

为什么下面的代码会编译并执行,但不会在输出中打印任何内容,

    int  i = 0;
    printf(i = 0);

但这会产生运行时错误,

    int  i = 0;
    printf(i = 1);

5 个答案:

答案 0 :(得分:2)

i = 0函数中的表达式i = 1printf将评估为01(并且i将初始化为{{分别为1}}和0)。因此,在表达式评估之后的1语句之上将等同于

printf

printf(0);  // To be clear, the `0` here is not a integer constant expression.

分别。

printf(1); 0都将被视为1语句中的地址,它将尝试从这些地址中获取字符串。但是,printf0都是未分配的内存地址,访问它们将导致未定义的行为。

答案 1 :(得分:2)

int  i = 0;
printf(i = 0);

printf的第一个参数必须是指向格式字符串的char*值。你给它一个int。这就是问题所在。 printf(i = 0)printf(i = 1)之间的行为差​​异在很大程度上无关紧要;两者都是同样错误的。 (可能第一个传递空指针,printf以某种方式检测并处理空指针,但这会分散真实问题。)

如果您想打印i = 0的值,这是正确的方法:

printf("%d\n", i = 0);

你在论证中有副作用(i = 0是作业而不是比较),这是合法但风格不佳。

如果您有必需的#include <stdio.h>,那么您的编译器必须至少警告您类型不匹配。

如果您没有#include <stdio.h>,那么您的编译器几乎肯定会在没有声明的情况下警告调用printf。 (严格要求C89 / C90编译器警告这一点,但任何体面的编译器都应该这样,并且C99或C11编译器必须这样做。)

编译代码时,编译器可能会给您一个或多个警告。您未能在问题中包含这些警告。您也未能向我们展示完整的自包含程序,因此我们只能猜测您是否具有所需的#include <stdio.h>。如果你的编译器没有警告你这个错误,你需要找出如何要求它进行更好的诊断(我们可以帮助你解决这个问题而不知道你是哪个编译器&# 39;重新使用)。

答案 2 :(得分:0)

printf等待格式字符串作为其第一个参数。由于字符串(char *)只不过是指针,因此您提供了一个地址作为第一个参数。

在地址和整数隐式转换为彼此后,

printf(i = 0) 

(从printf的角度来看)与:

相同
printf( 0 )

相同
printf( NULL ) // no string given at all

如果你提供0作为参数,printf将优雅地处理该情况并且根本不做任何事情,因为0是保留地址,意思是nothing at all

但是printf( 1 )是不同的:printf现在在地址1处搜索一个字符串,该字符串不是您程序的有效地址,因此您的程序会引发分段错误。

[更新] 这个工作的主要原因是你需要知道的几个关于char数组,指针,赋值和printf本身如何工作的事实的组合:

  • 指针可以隐式转换为int,反之亦然,因此int值17例如转换为内存地址0x00000011(17),恕不另行通知。这是因为C非常接近硬件并允许您使用内存地址进行计算。实际上,内部的int(或更具体:一个特殊类型的整数)和指针是相同的,只是使用不同的语法。当将代码从32位移植到64位架构时,这会导致很多问题,但这是另一个主题。

  • 作业与比较不同:i = 0i == 0的含义完全不同。当i == 0包含值0i = 0返回... 0时,b = 3会返回 true 。这是为什么?您可以连接例如以下变量赋值:

    a = b = 3;

首先,执行3,再次返回a,然后将其分配给while( (data = get_Item()) ) 。这对于测试数组中是否有更多项目的情况非常方便:

NULL

这现在导致下一点:

  • false与0相同(也与NULL相同)。对于整数和指针可以相互转换的事实(或更好:在物理上是相同的,请参阅上面的我的评论),有一个名为pointing nowhere的保留值,意思是:0x00000000。该值定义为虚拟地址import javax.swing.*; import javax.swing.filechooser.FileSystemView; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Insets; import java.awt.Toolkit; import java.awt.event.*; import java.beans.*; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Random; public class ProgressBarTest extends JPanel implements ActionListener, PropertyChangeListener { JButton browse, search; JTextField directory; JList<File> results; JScrollPane scrollPane; JProgressBar progressBar; File file; List<File> fileList = new ArrayList<File>(); Task task; private class MyCellRenderer extends DefaultListCellRenderer { public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) { Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); JLabel l = (JLabel)c; File f = (File)value; l.setText(f.getName()); l.setPreferredSize(new Dimension(130, 20)); l.setIcon(FileSystemView.getFileSystemView().getSystemIcon(f)); l.setToolTipText(f.getName()); l.setBorder(BorderFactory.createEmptyBorder(3,3,3,3)); return l; } } private class Task extends SwingWorker<Void, Void> { @Override public Void doInBackground() { file = new File(directory.getText().trim()); GetFiles(file); File[] fileArray = fileList.toArray(new File[0]); results.setListData(fileArray); int progress = 0; setProgress(0); try { Thread.sleep(1000); } catch (InterruptedException ignore) {} while (progress < 100) { try { Thread.sleep(1000); } catch (InterruptedException ignore) {} progress += 10; setProgress(Math.min(progress, 100)); } return null; } @Override public void done() { Toolkit.getDefaultToolkit().beep(); Toolkit.getDefaultToolkit().beep(); search.setEnabled(true); JOptionPane.showMessageDialog(null, "Finished!"); } } public ProgressBarTest() { super(new BorderLayout()); browse = new JButton("Browse"); browse.setActionCommand("browse"); browse.addActionListener(this); search = new JButton("Search"); search.setActionCommand("search"); search.addActionListener(this); directory = new JTextField(20); directory.setEnabled(false); file = new File(System.getProperty("user.home")); results = new JList<File>(file.listFiles()); results.setCellRenderer(new MyCellRenderer()); results.setLayoutOrientation(JList.HORIZONTAL_WRAP); results.setVisibleRowCount(-1); scrollPane = new JScrollPane(results, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); scrollPane.setPreferredSize(new Dimension(408, 100)); progressBar = new JProgressBar(0, 100); progressBar.setValue(0); progressBar.setStringPainted(true); JPanel panel = new JPanel(); panel.add(browse); panel.add(directory); panel.add(search); JPanel otherPanel = new JPanel(); otherPanel.add(scrollPane); JPanel newPanel = new JPanel(); newPanel.add(progressBar); add(panel, BorderLayout.PAGE_START); add(otherPanel, BorderLayout.CENTER); add(newPanel, BorderLayout.PAGE_END); setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createEtchedBorder())); } @Override public void propertyChange(PropertyChangeEvent event) { if (event.getPropertyName() == "progress") { int progress = (Integer)event.getNewValue(); progressBar.setIndeterminate(false); progressBar.setValue(progress); } } // End propertyChange() @Override public void actionPerformed(ActionEvent event) { if (event.getActionCommand().equals("browse")) { JFileChooser fileChooser = new JFileChooser(System.getProperty("user.home")); fileChooser.setDialogTitle("What folder?"); fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); fileChooser.showOpenDialog(this.getParent()); directory.setText(fileChooser.getSelectedFile().getPath()); } else if (event.getActionCommand() == "search") { progressBar.setIndeterminate(true); search.setEnabled(false); task = new Task(); task.addPropertyChangeListener(this); task.execute(); } } // End actionPerformed() private static void CreateAndShowGUI() { JFrame frame = new JFrame("ProgressBar Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JComponent contentPane = new ProgressBarTest(); contentPane.setOpaque(true); frame.setContentPane(contentPane); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } private void GetFiles(File file) { for (File f : file.listFiles()) { if (f.isDirectory()) { fileList.add(f); GetFiles(f); } else if (f.isFile()) { fileList.add(f); } } } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { CreateAndShowGUI(); } // End run() }); // End Runnable() } // End main } // end ProgressBarTest (32位)。因此,如果您愿意,请为需要指针的函数提供0,您可以提供指针。

  • char *是一个指针。与char []相同(行为和分配中存在轻微的逻辑差异,但在内部它们基本相同)。 printf需要一个char *,但是你提供了一个int。这不是问题,如上所述,int将被解释为地址。几乎每个(编写良好的)函数都将指针作为参数,将对这些参数进行健全性检查。 printf没有排除:如果它检测到空指针,它将处理该情况并以静默方式返回。但是,当提供不同的东西时,无法知道它是否真的不是一个有效的地址,因此printf需要完成它的工作,在尝试通过分段错误寻址0x00000001的内存时被内核中断。

这是一个很长的解释。

顺便说一下:这只适用于32位指针(编译为32位二进制)。对于64位计算机上的long int和指针也是如此。但是,这是编译器的问题,它如何转换您提供的表达式(通常,int值0被隐式转换为long int值0,然后在分配时用作指针地址,反之亦然'在没有明确演员的情况下工作。)

答案 3 :(得分:0)

printf需要一个const char *作为输入,而你给它一个int

答案 4 :(得分:0)

<块引用>

为什么下面的代码可以编译并执行,但在输出中不打印任何内容?

d:\ |-- home
      |-- site
          |-- wwwroot
              |-- App_Data
                  |-- jobs
                      |-- triggered
                      | -- continuous

这个问题包含了一个错误的前提。在任何现代 C 编译器上,这个明显错误的代码至少会产生一个错误。