C - 无意中通过函数更改字符串

时间:2015-09-17 23:02:00

标签: c string pointers methods

我最近一直在使用一些C而且我现在比较新。我的主要问题是我传递给函数的字符串无意中被更改为一组新的随机字符。我很难解释我的问题,因为我有一堆代码,我不能分享它。但问题出在以下几个方面:

这个代码在main函数中:

char* name = "@";
Var v = NewVar(name, 0);
printf("%s\n", name);

打印:

Creating New Value w/ Name: @ 
@

- 应该打印的是什么。但是,这段代码(在另一个函数中):

printf("Before: %s\n", split[counter]);
Var v = NewVar(split[counter], 0);
printf("After: %s\n", split[counter]);

打印:

Before: hi
Creating New Value w/ Name: �
After:�P�

“split”(来自上面的代码)只是一个定义如下的二维数组:

char** split = str_split(path, '/')

“NewVar()”函数如下:

Var NewVar(char *name, int value){
    printf("Creating New Value w/ Name: %s\n", name);
    Var v;
    v.value = value;
    v.name = name;
    v.varsLen = 0;
    v.vars = (Var*)malloc(sizeof(struct Vars));
    return v;
}

我以前多次注意到这个问题,但到目前为止我已经解决了这个问题。任何关于为什么这样做的建议或解释都会非常有用。

编辑: 这是一个完整的例子:

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

char** strSplit(char* base, const char* delim){
    char* result[0];
    char *token;
    char str[strlen(base)];
    strcpy(str, base);
    token = strtok(str, delim); 
    int counter = 0;
    while( token != NULL ) {
        result[counter] = token;
        token = strtok(NULL, delim);
        counter++;
    }
    char** split = malloc(counter * sizeof(char*));
    for(int i = 0; i < counter; i++){
        split[i] = malloc(sizeof(result[i])+1);
        result[i][strlen(result[i])] = '\0';
        split[i] = result[i];
    }
    split[counter] = 0;
    return split;
}

typedef struct Vars{
    char* name;
    struct Vars* vars;
    int value;
    int varsLen;
} Var;

Var NewVar(char *name, int value){
    printf("Creating New Value w/ Name: %s\n", name);
    Var v;
    v.value = value;
    v.name = name;
    v.varsLen = 0;
    v.vars = (Var*)malloc(sizeof(struct Vars));
    return v;
}

void test(char** split){
    char* name = split[0];
    Var v = NewVar(name,0);
    printf("After: %s\n", name);
}

int main(int argc, char const *argv[])
{
    char* name = "@";
    Var v = NewVar(name, 0);
    printf("%s\n", name);
    char** split = strSplit("@/dir1/dir2", "/");
    printf("Before: %s\n", split[0]);
    test(split);
    return 0;
}

打印:

Creating New Value w/ Name: @
@
Before: @
Creating New Value w/ Name: @
After: 

2 个答案:

答案 0 :(得分:1)

让我们剖析str_split(),我们呢?

char** strSplit(char* base, const char* delim){
    char* result[0];

我们的第一个错误。您不能拥有零长度数组。此外,您稍后使用该数组,因此即使您可能具有零长度数组,也无法将其编入索引。

    char *token;
    char str[strlen(base)];
    strcpy(str, base);

下一个错误。 str太小而无法容纳base,因为strlen()不计算空终止符。

    token = strtok(str, delim); 
    int counter = 0;
    while( token != NULL ) {
        result[counter] = token;

滥用result

        token = strtok(NULL, delim);
        counter++;
    }
    char** split = malloc(counter * sizeof(char*));

请记住这一点,split有足够的空间容纳counter char * ...

    for(int i = 0; i < counter; i++){
        split[i] = malloc(sizeof(result[i])+1);

混合strlen()sizeof()

        result[i][strlen(result[i])] = '\0';

无用。如果somestring[strlen(somestring)]尚未'\0',则不会是strlen(somestring)

        split[i] = result[i];

这会泄漏为split[i]分配的内存,并保留指向str的指针,该指针在函数返回时超出范围。替换为strcpy()

    }
    split[counter] = 0;

你还记得split有多少空间吗?

    return split;
}

答案 1 :(得分:0)

您不知道name的传入值会发生什么。如果它是在堆栈上分配的,它将被覆盖。 v.name时使用strcpy,您将是安全的。