Char指针:创建动态字符串数组,赋值并传递给其他函数和其他小兄弟--C

时间:2018-04-08 19:20:56

标签: c string pointers malloc

我正在研究与动态内存一起使用的指针,我已经完成了一个MCVE代码,我创建了一个动态字符串数组(指向char的指针),使用malloc初始化它,赋值,将它发送到打印它们的函数和返回ok,然后是空闲内存(完整代码在帖子的底部。我建议在问题出现前查看完整代码)。

这样做,我有疑问:

  • 字符串数组应该像:?

    char **stringArray = NULL;
    stringArray = malloc(NUM_OF_ELEMENTS*sizeof(char)); 
    for (i = 0; i < NUM_OF_ELEMENTS; i++)
        stringArray[i] = malloc((STRING_LENGTH+1)*sizeof(char));
    /*
        FIRST: Init a double pointer to char
        SECOND: Create number of elements of the array (number of strings)
                When is created the number of elements... is not needed end it with '\0' char, right?
                When malloc is done... is needed mult it *sizeof(char)? In case it is not like that, is needed mult it *sizeof(anything)?
        THIRD: Create length of each string
    */
    
  • 输入(由用户或手动)是否正确完成?

    // Creating elements
    // User input
    for (i = 0; i < NUM_OF_ELEMENTS-1; i++) {
        printf("Input: %i with letters (One, Two,..): ", i+1);
        gets(userInput);
        strcpy(stringArray[i], userInput); // stringArray[0] = "One"; stringArray[1] = "Two"
    }
    // Manually
    strcpy(stringArray[NUM_OF_ELEMENTS-1], "Three"); // stringArray[2] = "Three"
    
  • 返回字符串的函数也应该是指向char的指针,对吗?

    char *functionWhichReturnsOneString() {
        return "string";
    }
    
  • 是否按值和引用正确传递/接收参数?

    printElementsOfStringArrayPassedByValue(stringArray) // Call to function
    char *printElementsOfStringArrayPassedByValue(char **stringArray) {
        int i = 0;
    
        for (i = 0; i < NUM_OF_ELEMENTS; i++)
            printf("%s\n", stringArray[i]);
    
        return "OK";
    }
    
    printElementsOfStringArray2PassedByReference(&stringArray) // Call to function
    char *printElementsOfStringArray2PassedByReference(char ***stringArray) {
        int i = 0;
    
        for (i = 0; i < NUM_OF_ELEMENTS; i++)
            printf("%s\n", (*stringArray)[i]); // Is it equal to: *((*stringArray)+i) ?
    
        return "OK";
    }
    
    • 相等:(*stringArray)[i])和:*((*stringArray)+i),对吧?


完整代码是:

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

#define NUM_OF_ELEMENTS 3
#define STRING_LENGTH 35

char *printElementsOfStringArrayPassedByValue(char **stringArray) {
    int i = 0;

    for (i = 0; i < NUM_OF_ELEMENTS; i++)
        printf("%s\n", stringArray[i]);

    return "OK";
}

char *printElementsOfStringArray2PassedByReference(char ***stringArray) {
    int i = 0;

    for (i = 0; i < NUM_OF_ELEMENTS; i++)
        printf("%s\n", (*stringArray)[i]); // Is it equal to: *((*stringArray)+i) ?

    return "OK";
}

int main(void) {
    // Variables
    int i = 0;
    char userInput[STRING_LENGTH] = {'\0'};
    char **stringArray = NULL;
    char returnedValue[STRING_LENGTH] = {'\0'};

    // Creating array of strings
    stringArray = malloc(NUM_OF_ELEMENTS*sizeof(char)); // Here is correct: *sizeof(char)?; Is not needed \0 char?

    // Creating each element of the array
    for (i = 0; i < NUM_OF_ELEMENTS; i++)
        stringArray[i] = malloc((STRING_LENGTH+1)*sizeof(char));

    // Creating elements
        // User input
        for (i = 0; i < NUM_OF_ELEMENTS-1; i++) {
            printf("Input: %i with letters (One, Two,..): ", i+1);
            gets(userInput);
            strcpy(stringArray[i], userInput); // stringArray[0] = "One"; stringArray[1] = "Two"
        }
        // Manually
        strcpy(stringArray[NUM_OF_ELEMENTS-1], "Three"); // stringArray[2] = "Three"

    strcpy(returnedValue, printElementsOfStringArrayPassedByValue(stringArray)); // Pass by value and return a string
    printf("%s - Ended print 1\n", returnedValue);
    strcpy(returnedValue, printElementsOfStringArray2PassedByReference(&stringArray)); // Pass by reference and return a string
    printf("%s - Ended print 2\n", returnedValue);

    // Freeing memory
    for (i = 0; i < NUM_OF_ELEMENTS; i++) {
        free(stringArray[i]);
        stringArray[i] = NULL;
    }
    free(stringArray);
    stringArray = NULL;

    return 0;
}

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

- 方法没问题,但第一个sizeof参数错误(stringArray的类型为char **,而不是char *),最好使用带有malloc的sizeof:

 char **stringArray = NULL;
 stringArray = malloc(NUM_OF_ELEMENTS*sizeof(*stringArray)); 
 for (i = 0; i < NUM_OF_ELEMENTS; i++)
     stringArray[i] = malloc((STRING_LENGTH+1)*sizeof(*stringArray[i]));

对于编程中的母版,最好使用calloc来处理整数溢出:

 char **stringArray = NULL;
 stringArray = calloc(NUM_OF_ELEMENTS, sizeof(*stringArray)); 
 assert(stringArray != NULL);
 for (i = 0; i < NUM_OF_ELEMENTS; i++) {
     stringArray[i] = calloc(STRING_LENGTH+1, sizeof(*stringArray[i]));
     assert(stringArray[i] != NULL); 
 }

- 是的,不要使用获取。擦除从内存中获取。使用fgets(userInput, sizeof(userInput), stdin);
- 泡芙,这很糟糕。它可能工作,它可能不起作用,取决于你的编译器和机器,并且为了更好,不要返回指向string literalcompound literals的指针。当您创建(本地,具有自动存储持续时间)字符串文字时,它仅存在于块的末尾。所以这样的函数会返回一个指向字符串的指针,但是一旦函数退出,你就不知道该字符串是否存在,因为在functino返回后字符串停止存在。
有两种选择。一:声明返回的字符串具有静态存储持续时间,因此该变量将比函数更长(这是返回错误描述字符串的好选项):

static char *string_to_return = "string";
char *functionWhichReturnsOneString_global() {
    return string_to_return;
}
char *functionWhichReturnsOneString_static() {
    static char *string_to_return_2 = "string";
    return string_to_return;
}

这样,string_to_return具有静态存储持续时间,并且全局可用。其他方法是使用malloc(或strdup)为字符串分配内存并返回指向该内存的指针(记得以后释放它(!)):

char *functionWhichReturnsOneString_malloc() {
    char *string_to_return = malloc(sizeof("string"));
    memcpy(string_to_return, "string", sizeof("string"));
    return string_to_return;
}
char *functionWhichReturnsOneString_strdup() {
    return strdup("string");
}

- 这是有效的,但功能完全相同。 stringArray是一个指向字符数组的指针数组。它是一个指针,指向一个指针数组,每个指针指向一个字符数组。将stringArray传递给函数就足以修改存储在数组中的字符(如stringArray指向这些数组)和ex。调整这些数组的大小。如果你传递&amp; stringArray,你的函数可能会改变数组的数量(即NUM_OF_ELEMENTS)(不是特定数组中的字符数,而是自己的数组数)。你可以做*stringArray = realloc(*stringArray, (NUM_OF_ELEMENTS+20)*sizeof(**stringArray));
- 是的表达式A[B]等于B[A]等于*(B+A)。有趣的是,这也等于:*i[*stringArray],但这种形式会伤害我的眼睛。