繁体   English   中英

C - 打印字符串中每个字符的 ASCII 值

[英]C - Print ASCII Value for Each Character in a String

我是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);
}

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

#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!
}

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

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


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

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

您提供给scanf的参数是错误的,但意外地起作用 - 当它需要一个指向char的指针时,您正在传递一个指向数组的指针。 它之所以有效,是因为指向数组的指针指向数组的第一个元素。 幸运的是,这是一个简单的修复,一个类型的数组可以传递给一个 function 期望一个指向该类型的指针 - 据说它“衰减”到一个指针。 所以你可以只传递name

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


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

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);

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

注意: strlen通常不安全地用于可能未正确以空值终止的任意字符串,因为它会一直读取直到找到零字节,但我们在 C11 中只能获得可移植的边界检查版本strnlen_s 在这种情况下,我们也知道字符串是空终止的,因为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 的手册 memory 管理功能,例如mallocrealloc ,这并不是特别困难,但要更加小心避免 memory 泄漏等问题。

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

如果我们需要编写代码来获取字符串中所有元素的 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 值存储在一个新变量中,我们需要声明一个 integer 变量并将其分配给字符。 通过这种方式,integer 变量存储字符的 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);
        
    }
}

我希望这个答案对你有所帮助......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM