指向c中字符数组的指针

时间:2017-09-08 10:48:12

标签: c arrays

以下程序为值9001提供相同的输出。它应该为第一部分打印9,为第二部分打印1。函数words()采用正确的值并根据需要返回适当的值。但是在打印出现问题时它并没有打印出函数传递的值。

感谢您的帮助。

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

char * words(int n);
const char * twenty[] = { "One ","Two ","Three ","Four ","Five ","Six 
","Seven ","Eight ","Nine ","Ten ","Eleven ","Twelve ",
"Thirteen ","Fourteen ","Fifteen ","Sixteen ","Seventeen ","Eighteen 
","Nineteen ","Twenty " };
const char * thirty[] = { "Thirty ","Fourty ","Fifty ","Sixty ","Seventy 
","Eighty ","Ninty " };

int main() {
    //get input from user to print no to words
    printf("Give no :");
    int x = 0;
    scanf("%d", &x);
    char * answer[] = { "","" };
    if (x < 0 || x > 999999) 
        printf("Give no between 1 and 999999\n");
    else {
        if (x / 1000 > 0) {
            answer[0] = words(x / 1000);
            answer[1] = words(x % 1000);
        }
        else 
            answer[0] = words(x % 1000);
        printf("Frist part is : %s\n", answer[0]);
        printf("Second part is : %s\n", answer[1]);
    }
    return 0;
}

char * words(int n) {
    char * ans = "";
    if (n == 0) 
        return ans;
    if (n / 100 > 0) 
        ans = strcat(twenty[n / 100 - 1], "Hundred ");
    if (n % 100 < 21 && n % 100 > 0) 
        ans = strcat(ans, twenty[n % 100 - 1]);
    else{
        if (n % 100>0) 
            ans = strcat(ans, thirty[(n % 100) / 10 - 3]);
        if (n % 10>0) 
            ans = strcat(ans, twenty[`enter code here`(n % 10) - 1]);
    }
    return ans;
};

3 个答案:

答案 0 :(得分:0)

在您的words()功能中,您无法做到,

strcat(ans, ....) 

strcat(twenty[n / 100 - 1], ...)

ans中的twenty和元素没有足够的内存来容纳那么多字符。

其中一种方法是为ans分配缓冲区并使用它来返回单词。不要在twenty[]中重写字符串。

int max_ans_len = 1000;
char *ans = malloc(sizeof(char) * max_ans_len);
...

并且不要再次将strcat()的返回值分配给ans。另外,请确保不要在其中写入超过max_ans_len的内容,并在使用完毕后将其释放。

答案 1 :(得分:0)

以前的答案有点忽略了为什么你不能追加到ans。没有足够空间这一事实并不重要。更重要的是内存是只读的。例如,gcc 7.2生成的汇编程序看起来像

        .section        .rodata
.LC0:
        .string ""

rodata - 只读数据。如果您尝试写入此内容,则会出现分段错误。

例如

#include <string.h>

void foo()
{
   char *ans = "\0234567890";
   strcat(ans, "string");
}

int main()
{
   foo();
}

ans指向的10个字节现在足以包含num终止的"string"的7个字节。但这仍然会导致分段错误。

答案 2 :(得分:-1)

1)char* ans = "";声明

的问题

存在一些误解,特别是在char* words(int n)函数内部。如果我们查看description of the strcat()函数,我们会看到:

  

追加src指向的以null结尾的字节字符串的副本   dest指向的以null结尾的字节字符串的结尾。该   character src [0]替换dest末尾的null终止符。该   结果字节字符串以空值终止。

     

如果,则行为未定义   目标数组不足以容纳 src 的内容   和dest 以及终止空字符。行为未定义   如果字符串重叠。如果dest或者,行为是不确定的   src不是指向以null结尾的字节字符串的指针。

这是因为char* ans = "";函数中的words(),实际上与char ans[1] = { '\0' };相同。任何至少包含一个字符的单词都无法容纳。

因此,您应该重新声明ans数组,如下所示:

char* ans = calloc(100, sizeof(char));

现在,我们将能够返回ans因为它不是局部变量,并且它还有相当多的空间(100个字符)。感谢calloc(),它充满了零 - 这对于strcat非常有用。

注意:您必须为#include <stdlib.h>添加calloc()才能使用。

2)使用const char* twenty[]数组元素作为strdup

目的地的问题

第二个问题在这里:

ans = strcat(twenty[n / 100 - 1], "Hundred ");

在这里,您尝试在"Hundred "字符串的末尾连接twenty[n / 100 - 1] - 我认为这是您的错字,无论如何,它不应该主要因为twenty数组而完成是const - 不应修改。

3)释放动态分配的内存

最后,我们需要释放calloc()函数内words()分配的内存。这可以通过在main()的末尾添加类似的内容来完成(当然在return语句之前):

if (strlen(answer[0]) > 0) {
    free(answer[0]);
}
if (strlen(answer[1]) > 0) {
    free(answer[1]);
}

4)结果程序

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

char* words(int n);
const char* twenty[] = { "One ", "Two ", "Three ", "Four ", "Five ", "Six", "Seven ", "Eight ", "Nine ", "Ten ", "Eleven ", "Twelve ",
    "Thirteen ", "Fourteen ", "Fifteen ", "Sixteen ", "Seventeen ", "Eighteen", "Nineteen ", "Twenty " };
const char* thirty[] = { "Thirty ", "Fourty ", "Fifty ", "Sixty ", "Seventy", "Eighty ", "Ninty " };

int main()
{
    //get input from user to print no to words
    printf("Give no :");
    int x = 0;
    scanf("%d", &x);
    char* answer[] = { "", "" };
    if (x < 0 || x > 999999)
        printf("Give no between 1 and 999999\n");
    else {
        if (x / 1000 > 0) {
            answer[0] = words(x / 1000);
            answer[1] = words(x % 1000);
        } else
            answer[0] = words(x % 1000);
        printf("Frist part is : %s\n", answer[0]);
        printf("Second part is : %s\n", answer[1]);
    }
    if (strlen(answer[0]) > 0) {
        free(answer[0]);
    }
    if (strlen(answer[1]) > 0) {
        free(answer[1]);
    }
    return 0;
}

char* words(int n)
{
    char* ans = calloc(100, sizeof(char));
    if (n == 0)
        return ans;
    //if (n / 100 > 0) ans = strcat(twenty[n / 100 - 1], "Hundred ");
    if (n % 100 < 21 && n % 100 > 0)
        ans = strcat(ans, twenty[n % 100 - 1]);
    else {
        if (n % 100 > 0)
            ans = strcat(ans, thirty[(n % 100) / 10 - 3]);
        if (n % 10 > 0)
            ans = strcat(ans, twenty[(n % 10) - 1]);
    }
    return ans;
};

我已使用clang-format -style=WebKit main.c格式化结果代码。

它有效!

mirek@home:/hyper$ ./main
Give no :9001
Frist part is : Nine 
Second part is : One 
mirek@home:/hyper$

此外,valgrind报告没有内存错误:

mirek@home:/hyper$ valgrind --leak-check=full ./main
==7605== Memcheck, a memory error detector
==7605== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==7605== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==7605== Command: ./main
==7605== 
Give no :9001
Frist part is : Nine 
Second part is : One 
==7605== 
==7605== HEAP SUMMARY:
==7605==     in use at exit: 0 bytes in 0 blocks
==7605==   total heap usage: 4 allocs, 4 frees, 2,248 bytes allocated
==7605== 
==7605== All heap blocks were freed -- no leaks are possible
==7605== 
==7605== For counts of detected and suppressed errors, rerun with: -v
==7605== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
mirek@home:/hyper$