为什么下面的代码会编译并执行,但不会在输出中打印任何内容,
int i = 0;
printf(i = 0);
但这会产生运行时错误,
int i = 0;
printf(i = 1);
答案 0 :(得分:2)
i = 0
函数中的表达式i = 1
和printf
将评估为0
和1
(并且i
将初始化为{{分别为1}}和0
)。因此,在表达式评估之后的1
语句之上将等同于
printf
和
printf(0); // To be clear, the `0` here is not a integer constant expression.
分别。
printf(1);
和0
都将被视为1
语句中的地址,它将尝试从这些地址中获取字符串。但是,printf
和0
都是未分配的内存地址,访问它们将导致未定义的行为。
答案 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 = 0
和i == 0
的含义完全不同。当i == 0
包含值0
而i = 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 编译器上,这个明显错误的代码至少会产生一个错误。