【问题标题】:C - Print ASCII Value for Each Character in a StringC - 为字符串中的每个字符打印 ASCII 值
【发布时间】:2020-02-01 10:58:31
【问题描述】:

我是C 的新手,我正在尝试编写一个程序来打印用户输入的名称中每个字母的ASCII 值。我尝试将字母存储在一个数组中,并尝试分别打印每个 ASCII 值和名称的字母,但由于某种原因,它只打印第一个字母的值。

例如,如果我写“Anna”,它只会打印 65,而不是名称中其他字母的值。我认为这与我在for 循环中的sizeof(name)/sizeof(char) 部分有关,因为当我单独打印它时,它只打印出1。

我不知道如何解决它:

#include <stdio.h>

int main(){

    int e;
    char name[] = "";
    printf("Enter a name : \n");
    scanf("%c",&name);
    for(int i = 0; i < (sizeof(name)/sizeof(char)); i++){
        e = name[i];
        printf("The ASCII value of the letter %c is : %d \n",name[i],e);
    }
    int n = (sizeof(name)/sizeof(char));
    printf("%d", n);
}

【问题讨论】:

  • sizeof(name)/sizeof(char) 并不像您认为的那样。 name 也是一个 char 数组,可以只包含一个字符。
  • 查看strlen()scanf("%s") 和字符串的内存分配,
  • 数组在 C 中不会按需增长。您需要确定要处理的最大字符串大小,并在其中显式编程。

标签: c arrays for-loop ascii


【解决方案1】:

这是一个更正、带注释的版本:

#include <stdio.h>
#include <string.h>

int main() {
    int e;
    char name[100] = ""; // Allow for up to 100 characters
    printf("Enter a name : \n");
//  scanf("%c", &name); // %c reads a single character
    scanf("%99s", name); // Use %s to read a string! %99s to limit input size! 
//  for (int i = 0; i < (sizeof(name) / sizeof(char)); i++) { // sizeof(name) / sizeof(char) is a fixed value!
    size_t len = strlen(name); // Use this library function to get string length
    for (size_t i = 0; i < len; i++) { // Saves calculating each time!
        e = name[i];
        printf("The ASCII value of the letter %c is : %d \n", name[i], e);
    }
    printf("\n Name length = %zu\n", strlen(name)); // Given length!
    int n = (sizeof(name) / sizeof(char)); // As noted above, this will be ...
    printf("%d", n);                 // ... a fixed value (100, as it stands).
    return 0; // ALWAYS return an integer from main!
}

但也请阅读您问题中给出的 cmets!

【讨论】:

  • 您的答案可以改进...如果用户输入的字符超过 99 个会怎样?您可以使用scanf("%99s", name) 避免缓冲区溢出,或者更好的是,使用fgets,此外,sizeof char 始终为 1,它返回 size_t(不是 int
  • 你的意思是隐式转换为int,你是对的,但最好使用size_tprintf("%zu\n", sizeof(name)) 就足够了,因为sizeof char 始终是1,你不要'不需要分开。
  • 另一方面,即使现代编译器会对此进行优化,但在每次迭代时计算 strlen(name) 并不是一个好主意,您可以切换到:for (size_t i = 0, n = strlen(name); i &lt; n; i++) ...
【解决方案2】:

这是一个相当长的答案,请随意跳到代码示例的末尾。


首先,通过初始化具有未指定长度的char 数组,您使该数组的长度为 1(它只包含空字符串)。这里的关键问题是 C 中的数组是固定大小的,所以名字不会变大。

其次,格式说明符%c 导致scanf 只读取一个字节。这意味着即使你创建了一个更大的数组,你也只会读取一个字节。

你给scanf 的参数是错误的,但意外地起作用了——当它需要一个指向char 的指针时,你传递了一个指向数组的指针。它之所以有效,是因为指向数组的指针指向数组的第一个元素。幸运的是,这是一个简单的解决方法,一个类型的数组可以传递给一个期望指向该类型的指针的函数——据说它“衰减”到一个指针。所以你可以直接传递name

作为这两个操作的结果,您现在遇到了name 的长度为 1 的情况,并且您已经读取了其中的一个字节。下一个问题是sizeof(name)/sizeof(char) - 在您的程序中这将始终等于 1。 sizeof char 被定义为始终等于 1,因此将其用作除数不会产生任何影响,而且我们已经知道 sizeof name 等于 1。这意味着您的 for 循环只会从数组中读取一个字节。出于完全相同的原因,n 等于 1。这本身并没有错,只是可能不是您所期望的。


可以通过多种方式解决此问题,但我将展示其中一种。首先,你不想像你一样初始化name,因为它总是创建一个大小为 1 的数组。相反,你想手动为数组指定一个更大的大小,例如 100 个字节(其中最后一个一个将专用于终止空字节)。

char name[100];
/* You might want to zero out the array too by eg. using memset. It's not
   necessary in this case, but arrays are allowed to contain anything unless
   and until you replace their contents.

   Parameters are target, byte to fill it with, and amount of bytes to fill */
memset(name, 0, sizeof(name));

其次,如果您只是从标准输入中读取字节字符串而不是更复杂的格式化字符串,那么您根本不需要使用scanf。你可以例如。使用fgets 从标准输入中读取整行,尽管其中还包括换行符,我们必须去掉它。

/* The parameters are target to write to, bytes to write, and file to read from.

   fgets writes a null terminator automatically after the string, so we will
   read at most sizeof(name) - 1 bytes.
*/
fgets(name, sizeof(name), stdin);

现在您已经记住了这个名字。但是name 数组的大小没有改变,所以如果您按原样使用其余代码,您会收到很多消息说The ASCII value of the letter is : 0。要获得有意义的字符串长度,我们将使用strlen

注意:strlen 通常不安全地用于可能未正确以空值结尾的任意字符串,因为它会一直读取直到找到零字节,但我们只能得到一个可移植的边界检查版本 strnlen_s in C11。在这种情况下,我们也知道字符串是以 null 结尾的,因为 fgets 处理它。

/* size_t is a large, unsigned integer type big enough to contain the
   theoretical maximum size of an object, so size functions often return
   size_t.

   strlen counts the amount of bytes before the first null (0) byte */
size_t n = strlen(name);

现在我们有了字符串的长度,我们可以检查最后一个字节是否是换行符,如果是则删除它。

/* Assuming every line ends with a newline, we can simply zero out the last
   byte if it's '\n' */
if (name[n - 1] == '\n') {
    name[n - 1] = '\0';
    /* The string is now 1 byte shorter, because we removed the newline.
       We don't need to calculate strlen again, we can just do it manually. */
    --n;
}

循环看起来非常相似,因为它一开始就很好。大多数情况下,我们希望避免比较有符号的int 和无符号的size_t 可能出现的问题,因此我们还将i 设为size_t

for (size_t i = 0; i < n; i++) {
    int e = name[i];
    printf("The ASCII value of the letter %c is : %d \n", name[i], e);
}

把它们放在一起,我们得到

#include <stdio.h>
#include <string.h>

int main() {

    char name[100];
    memset(name, 0, sizeof(name));
    printf("Enter a name : \n");
    fgets(name, sizeof(name), stdin);

    size_t n = strlen(name);
    if (n > 0 && name[n - 1] == '\n') {
        name[n - 1] = '\0';

        --n;
    }

    for (size_t i = 0; i < n; i++){
        int e = name[i];
        printf("The ASCII value of the letter %c is : %d \n", name[i], e);
    }


    /* To correctly print a size_t, use %zu */
    printf("%zu\n", n);

    /* In C99 main implicitly returns 0 if you don't add a return value
       yourself, but it's a good habit to remember to return from functions. */
    return 0;
}

这应该可以正常工作。


补充说明:

  • 此代码应该是有效的 C99,但我认为它不是有效的 C89。如果您需要写入较旧的标准,您需要做一些不同的事情。幸运的是,如果你告诉编译器你想使用哪个标准,你的编译器应该会警告你这些问题。 C99 可能是这些天的默认设置,但旧代码仍然存在。

  • 像这样将字符串读入固定大小的缓冲区有点不灵活,因此在实际情况下,您可能希望有一种方法可以根据需要动态增加缓冲区的大小。这可能需要您使用 C 的手动内存管理功能,例如 mallocrealloc,这并不是特别困难,但要更加小心以避免出现内存泄漏等问题。

  • 不能保证您正在读取的字符串采用任何特定编码,并且 C 字符串对于处理未以单字节编码编码的文本并不理想。支持“宽字符串”,但您可能更经常处理包含 UTF-8 的 char 字符串,其中单个代码点可能是多个字节,甚至可能不代表单个字母。在更通用的程序中,您应该牢记这一点。

【讨论】:

    【解决方案3】:

    如果我们需要编写代码来获取字符串中所有元素的 ASCII 值,那么我们需要使用 "%d" 而不是 "%c"。通过这样做 %d 获取以下字符的相应 ascii 值。 如果我们只需要打印字符串中每个字符的 ascii 值。然后这段代码就可以工作了:

    #include <stdio.h>
    char str[100];
    int x;
    int main(){
        scanf("%s",str);
        for(x=0;str[x]!='\0';x++){
            printf("%d\n",str[x]);
        }
    }
    

    要将字符的所有对应ASCII值存储在一个新变量中,我们需要声明一个整数变量并将其分配给字符。通过这种方式,整数变量存储字符的 ascii 值。代码是:

    #include <stdio.h>
    char str[100];
    int x,ascii;
    int main(){
        scanf("%s",str);
        for(x=0;str[x]!='\0';x++){
            ascii=str[x];
            printf("%d\n",ascii);
            
        }
    }
    

    希望这个回答对你有所帮助.....?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-29
      • 2012-09-12
      • 2017-12-20
      • 2016-12-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多