C ++入门问题

时间:2014-07-20 22:46:42

标签: c++ arrays c++11 size-t

我目前正在阅读Lahoie,Lippman和Moo的第五版C ++ Primer,并且一直在努力解决一些问题。

首先,我只想确认,在使用任何cctype函数时,我必须确保包含标题,对吧?因为,最初,我忘了包含它,但它仍然运行。这让我很困惑。

另外,我正在浏览一个不同的问题(我会去)并发现另一个问题哈哈!使用cctype中的任何内容时,我是否应该将其写为std::/write using std::,例如如果我使用tolower在每个实例上写std::tolower /为它写一个using语句。这是有道理的,因为它确实说它们是“在std命名空间中定义的”但我没有意识到并且一直在编写它而没有出现问题。我猜size_t类似,对吧?

说到size_t,我有一个问题。这是我的代码:

// Exercise Section 3.5.2., Exercise 3.30

#include <iostream>
#include <cstddef>

using std::cout; using std::endl;

int main()
{
    constexpr size_t num_size = 10;
    int num[num_size] = {};

    for (size_t n = 0; n < num_size; ++n) {
        num[n] = n;
        cout << num[n] << endl;
    }
    return 0;
}

因此,代码应该定义一个10 int s的数组,并为每个元素赋予与其在数组中的位置相同的值。

它运行正常,但我在num[n]=n部分收到错误。它说Implicit conversion loses integer precision: size_t (aka 'unsigned long') to int

我理解这意味着什么,但我的问题是本书说“当我们使用变量来下标数组时,我们通常应该定义该变量以键入size_t”。我做了这个,它给出了这个错误。它确实运行良好,但似乎可能会导致错误。

P.S。在此代码中,就像我上面提到的那样,我应该using std::size_t吗?

5 个答案:

答案 0 :(得分:4)

  

我必须包含标题,即使它没有吗?

是的,您必须始终包含至少一个标题,提供您需要的每个定义/声明,除非确保原型/类型定义,并将其直接放入源代码中。

某些标准标题可能包含其他标准标题,这可能会让您在某些时候变得松懈,但是在升级/移植到其他实现的那一天,您将会对它进行谴责。

  

我读了所有的声明和定义是“在std命名空间中定义的”,但我没有意识到并且一直在编写它并且没有出现问题。而我猜测size_t类似,对吧?

是的,它是一样的。由于兼容性,包含在C / Unicode中的<c...>标头也可以在全局名称空间中提供它们的符号。

  

17.6.1.2标题[headers]

     

1 C ++标准库的每个元素都在header.175中声明或定义(视情况而定)   2 C ++标准库提供了55个C ++库头,如表14所示   3 C标准库的设施在26个附加标题中提供,如表15所示   4除第18条至第30条和附件D中所述外,每个标题cname的内容应与C标准库(1.2)或C Unicode TR中指定的相应标题name.h的内容相同,如适当的,好像通过包含。但是,在C ++标准库中,声明(除了在C中定义为宏的名称除外)都在命名空间std的命名空间范围(3.3.6)内。 未指定这些名称是否首先在全局命名空间范围内声明,然后通过显式使用声明(7.3.3)注入命名空间std。
  5在C语言库中定义为宏的名称应在C ++标准库中定义为宏,即使C授予实现许可证作为函数。 [注意:在C中定义为宏的名称包括以下内容:assert,offsetof,setjmp,va_arg,va_end和va_start。 - 注意事项]
  6在C中定义为函数的名称应定义为C ++标准库中的函数.176
  7作为C ++中关键字或运算符的标识符不应在C ++标准库头中定义为宏.177   8 D.5,C标准库头文件,描述了在C ++程序中使用name.h(C头)表单的效果。 178

  

在我的示例程序中,我使用size_t作为数组索引。虽然我得到了警告,但这确实有效。我应该这样做,并且通常会导致错误吗?

嗯,正如您猜测的那样,名称空间std自然也是如此。

至于其余部分,有一个很好的短语:“好的建议伴随着理由”。

你应该使用std::size_t作为索引的原因是这种类型a)向读者发出信号,表明它是一个大小或索引,b)它保证足够大。 在您的情况下,低int,其最小保证最小值为2 15 -1将完全没问题。
另一种选择是在分配时投射到正确的类型。

答案 1 :(得分:2)

您将数组声明为

int num[num_size] = {};

这意味着它是int的数组,其中包含10个元素。

然后你说

for (size_t n = 0; n < num_size; ++n)
    num[n] = n;

请注意,n的类型为size_t,即unsigned long。因此,您将unsigned long值放入int数组中,因此它们会隐式转换为int值。

答案 2 :(得分:2)

标准头文件在全局命名空间中放入了大量内容。理想情况下他们不会,但他们会这样做。通常那是因为某些东西实际上是一个宏而不是一个typedef或函数。

您有时可以在不包含标题的情况下离开,因为您包含的其他标题包含缺少的标题。

答案 3 :(得分:2)

你问:

  

首先,我只想确认,在使用任何cctype函数时,我必须确保包含标题,对吧?

是的,这是对的。您可能间接获得一些函数声明或其他声明,但这不是可移植代码。您应该了解标准声明声明的位置,并在使用函数,类型等之前包含该头文件。

你问:

  

我猜是size_t的相似,对吧?

是的,您应该使用std::size_t

有一篇与该主题相关的SO帖子。浏览Difference between size_t and std::size_t

你问:

  

在这段代码中,就像我上面提到的那样,我应该使用std :: size_t吗?

在循环中,也可以使用int。使用std::size_t索引数组的建议是一个很好的建议,但不是不可侵犯的。

如果您选择size_t使用n,则可以使用static_cast将其转换为int以摆脱编译器警告/错误。< / p>

num[n] = static_cast<int>(n);

答案 4 :(得分:2)

  

我必须确保包含标题,对吧?因为,最初,我   忘了把它包括在内但它还在运行。

某些标准标头可以包含其他标头。但是,如果程序中使用了标头中的某些声明,则最好明确包含标头。它可能以这样的方式发生:在包含的头的其他实现中,不包括所需的头,编译器将发出错误。

  

。这是有道理的,因为它确实说它们是在...中定义的   std命名空间&#34;但我没有意识到并且没有写过它   并且没有问题。

C ++标准允许编译器将C标准函数放在全局命名空间中。虽然在这种情况下,最好明确指定名称空间std,在任何情况下都将声明函数。

至于最后一个问题,那么数组的元素具有类型int,而你为它们分配size_t类型的值时问题是类型int无法容纳所有值键入size_t,编译器会向您发出警告。您可以明确指定强制转换,以说明您知道自己在做什么的编译器。

num[n] = ( int )n;

num[n] = static_cast<int>( n );