如何传递给一个字符串的引用? [英] How to pass a reference to a string?

查看:160
本文介绍了如何传递给一个字符串的引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一切我读过关于 scanf函数获得与fgets 是,它们是有问题的;无论是与空格,溢出或复杂性。我要带一个介绍到C课程,因为我在Java等语言足够的编程经验有信心这样做,我决定创建我自己的函数使用从用户获取字符串输入的getchar ()功能。我的code的相关作品是如下:

 布尔get_string(字符提示[]的char *字符串)
{
    的printf(提示); //提示用户    //确保字符串分配存储空字符和重置它,如果它已经被初始化
    做{字符串=(字符*)malloc的(的sizeof(字符)); }而(字符串== NULL);    INT索引= 0;
    焦位置=的getchar();
    而(地方!='\\ n')//获取ENDL之前的所有字符
    {
        字符串=(字符*)的realloc(字符串的sizeof(字符串)+的sizeof(字符)); //创建数组中的房间
        在(string == NULL)返回false; //确保realloc的工作正常
        字符串[指数++] =到位; //放置在倒数第二个索引新的字符串
        地方=的getchar();
    }
    字符串[指数] ='\\ 0'; //结尾追加空字符    返回true; //操作成功
}

经过测试和调试,我设法弄清楚的是:


  1. 我的功能满足规范本地和参数字符串保存输入的字符串。

  2. 我用我的主要方法的的char * 指针没有被改变。叫我输入功能后,该指针的提领保持相同的初始值。

我是IM pression,因为我是通过一个函数指针,将治疗参数作为参考下。事实上,这是我在班上被教导。任何有识之士能有所帮助。

奖励积分奖励,如果:

您能告诉我为什么它不会让我自由我的的char * 指针为主。 (也许是因为它没有被通过同样的问题分配呢?)

我在做什么其他错误,如调用realloc的次数太多了?

请注意:我使用的是MSVC C89编译器和定义布尔,真假precompile


解决方案

  

我用我的主要方法的字符*指针没有被改变。叫我输入功能后,该指针的提领保持相同的初始值。


这是一些车次的人很多,如果用户想一个函数来更新参数当他们第一次开始写C.这是一个的指针的值,你必须通过一个指针的指针。

假设如下:

 无效美孚(T * P)
{
  * p值= NEW_VALUE(); //更新p为指向的东西
}空巴(无效)
{
  ŤVAL;
  富(放大器; VAL); //更新VAL
}

pretty简单 - 我们想要的函数写一个新值 VAL ,所以我们一个指针传递给 VAL 。现在更换输入 T 通过键入 R *

 无效美孚(R ** P)
{
  * p值= NEW_VALUE(); //更新p为指向的东西
}空巴(无效)
{
  R * VAL;
  富(放大器; VAL); //更新VAL
}

语义是完全一样的 - 我们正在编写一个新的价值 VAL 。所有这一切的改变是类型 VAL P 的。

所以,你的函数原型必须

 布尔get_string(字符提示[],CHAR **字符串)

因为要修改的指针的值字符串点。这也意味着,在你的函数体,你写 *字符串,而不是字符串

有关编写的malloc的preferred方法呼叫

  T * p =的malloc(sizeof的* P * number_of_elements);

  T * P;
...
p值= malloc的(sizeof的* P *元素的数目);

演员是不必要的,因为C89 1 ,并在C89其实可以燮preSS一个有用的诊断。由于C99废除了隐含的 INT 声明,这不是大问题了,但它仍然是最好保留它。还要注意的sizeof的的操作;而不是一个类型的前pression像(字符),我们使用ex pression * P 。由于前pression类型 * P T ,那么的sizeof * p 给出了相同的结果,为的sizeof(T)。它不仅看起来更干净,但如果你决定更改 P 的类型,它降低了维护。

在你的情况, P *字符串,给我们

  *字符串=的malloc(sizeof的**字符串);

由于的realloc 是一个潜在的昂贵的操作,你真的不想叫它为每一个新角色。一个更好的策略是必要的,以最初分配应处理大多数情况下的缓冲器,然后,通过电流大小的一些因素进行扩展(如加倍它)。在这种情况下,我会做类似如下:

 为size_t stringsize的= INITIAL_SIZE; //跟踪物理缓冲区大小*字符串=的malloc(sizeof的*串* stringsize的);
如果(!*字符串)
  //初始内存分配失败,恐慌而((地方=的getchar())='\\ n'和;!&安培;!=到位EOF)
{
   如果(指数== stringsize的)
   {
     //双缓冲区大小
     字符* TMP = realloc的(*字符串,sizeof的**字符串*(stringsize的* 2));
     如果(TMP)
     {
       *字符串= tmp目录;
       stringsize的* = 2;
     }
   }
   (*字符串)指数++] =到位;
}

这减少了调用到的realloc ,应最大限度地提高性能的总数。

此外,如果的realloc 失败,它将返回 NULL 并留在原地当前分配的缓冲区;但是,如果出现这种情况,你的真正的不想说结果分配回 *字符串,否则你会失去你只能参考该内存。你应该的总是的realloc 的结果分配给一个临时变量和前的分配回<$ C $检查它的 C> *字符串。

另外请注意,我们怎么下标 *字符串;由于标 [] 运营商具有较高的precedence比一元 * 操作符, *字符串[指数++] 会被解析为 *(字符串[指数++] ),这不是我们想要的 - 我们希望索引 *字符串,而不是字符串。所以,我们必须明确使用括号,给我们组 * 运营商

 (*字符串)指数++] =到位;



1。这是C ++有必要,但如果你正在写C ++,你应该使用操盘手。

Everything I've read about scanf, gets and fgets is that they are problematic; either with white space, overflow or complexity. I'm taking an intro to C course and because I have enough experience programming in Java and other languages to feel confident doing so, I decided to create my own function to obtain string input from the user using the getchar() function. The relevant pieces of my code are below:

bool get_string (char prompt[], char* string)
{
    printf(prompt); // Prompt the user

    // Ensure string is allocated to store the null character and reset it if it has been initialized
    do { string = (char*)malloc(sizeof(char)); } while (string == NULL);

    int index = 0;
    char place = getchar();
    while (place != '\n') // Obtain all characters before endl
    {
        string = (char*)realloc(string, sizeof(string) + sizeof(char)); // Create room in the array
        if (string == NULL) return false; // Ensure realloc worked correctly
        string[index++] = place; // Place the new string in the second to last index
        place = getchar();
    }
    string[index] = '\0'; // Append the null character at the end

    return true; // Operation succeeded
}

Through testing and debugging I'm managed to figure out that:

  1. My function meets specification locally, and the parameter string holds the entered string.
  2. The char* pointer I am using in my main method is not being altered. After calling my input function, the dereference of this pointer remains the same as its initial value.

I was under the impression that because I was passing a pointer to the function it would treat the parameter as by reference. In fact, this is what I was taught in the class. Any insight can help.

Bonus points awarded if:

You can tell me why it won't let me free my char* pointer in main. (Maybe because it hasn't been allocated via the same issue?)

What else I am doing wrong, such as calling realloc too many times?

NOTE: I am using the MSVC C89 compiler and define bool, true and false precompile.

解决方案

The char* pointer I am using in my main method is not being altered. After calling my input function, the dereference of this pointer remains the same as its initial value.

This is something that trips a lot of people up when they first start writing C. If you want a function to update a parameter that is a pointer value, you must pass a pointer to a pointer.

Assume the following:

void foo( T *p )
{
  *p = new_value(); // update the thing p is pointing to
}

void bar( void )
{
  T val;
  foo( &val ); // update val
}

Pretty straightforward - we want the foo function to write a new value to val, so we pass a pointer to val. Now replace the type T with the type R *:

void foo( R **p )
{
  *p = new_value(); // update the thing p is pointing to
}

void bar( void )
{
  R *val;
  foo( &val ); // update val
}

The semantics are exactly the same - we are writing a new value to val. All that's changed is the types of val and p.

So, your function prototype needs to be

bool get_string (char prompt[], char **string)

since you want to modify the pointer value that string points to. This also means that in the body of your function, you're writing to *string, not string.

The preferred method for writing a malloc call is

T *p = malloc( sizeof *p * number_of_elements );

or

T *p;
...
p = malloc( sizeof *p * number of elements );

The cast is unnecessary as of C891, and under C89 can actually suppress a useful diagnostic. Since C99 did away with implicit int declarations it's not much of an issue anymore, but it's still better to leave it off. Also notice the operand of sizeof; instead of a type expression like (char), we use the expression *p. Since the type of the expression *p is T, then sizeof *p gives the same result as sizeof (T). Not only does it look cleaner, but it reduces maintenance if you ever decide to change the type of p.

In your case, p is *string, giving us

*string = malloc( sizeof **string );

Since realloc is a potentially expensive operation, you really don't want to call it for every new character. A better strategy is to initially allocate a buffer that should handle most cases, then extend it by some factor of the current size (such as doubling it) as necessary. In this case, I'd do something like the following:

size_t stringSize = INITIAL_SIZE; // keeps track of the physical buffer size

*string = malloc( sizeof *string * stringSize );
if ( ! *string )
  // initial memory allocation failed, panic

while ((place = getchar()) != '\n' && place != EOF) 
{
   if ( index == stringSize )
   {
     // double the buffer size
     char *tmp = realloc( *string, sizeof **string * ( stringSize * 2 ) );
     if ( tmp )
     {
       *string = tmp;
       stringSize *= 2;
     }
   }
   (*string)[index++] = place; 
}  

This reduces the total number of calls to realloc, which should maximize your performance.

Also, if realloc fails, it will return NULL and leave the currently allocated buffer in place; however, if that happens, you really don't want to assign that result back to *string, otherwise you'll lose your only reference to that memory. You should always assign the result of realloc to a temporary variable and check it before assigning back to *string.

Also note how we subscript *string; since the subscript [] operator has higher precedence than the unary * operator, *string[index++] will be parsed as *(string[index++]), which isn't what we want - we want to index into *string, not string. So, we have to explicitly group the * operator using parentheses, giving us

(*string)[index++] = place;


1. It is necessary in C++, however, but if you're writing C++ you should be using the new operator instead.

这篇关于如何传递给一个字符串的引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆