为什么修改字符串的代码不起作用?

时间:2009-06-03 05:28:18

标签: c pointers char segmentation-fault access-violation

对于c样式的字符串,如何将char分配给字符指针指向的内存地址?例如,在下面的示例中,我想将num更改为“123456”,因此我尝试将p设置为'0'所在的数字,并尝试用'4'覆盖它。感谢。

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

int main()
{
    char* num = (char*)malloc(100);
    char* p = num;

    num = "123056";

    p = p+3;    //set pointer to where '4' should be
    p = '4';

    printf("%s\n", num );

    return 0;
}

5 个答案:

答案 0 :(得分:13)

首先,当你这样做时:

num = "123056";

您没有将字符串“123056”复制到malloc()分配的堆区域。在C中,指定一个char *指针,字符串文字值相当于将其设置为常量 - 即与:

相同
char str[] = "123056";

那么,你刚刚完成的是你已经放弃了对malloc()分配的100字节堆区域的唯一引用,这就是你的后续代码没有打印正确值的原因; “p”仍然指向由malloc()分配的堆区域(因为num在分配时指向它),但num不再存在。

我认为您实际上打算将复制字符串“123056”放入该堆区域。以下是如何做到这一点:

strcpy(num, "123056");

尽管如此,出于各种原因这是更好的做法:

strncpy(num, "123056", 100 - 1);  /* leave room for \0 (null) terminator */

如果你刚刚完成:

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

int     main(void) {
        char    *num = malloc(100);
        char    *p = num;

        strncpy(num, "123056", 100 - 1);

        p = p + 3;
        *p = '4';

        printf("%s\n", num);

       return 0;
} 

你会得到正确的结果:

123456

您可以签订此操作合同:

p = p + 3;
*p = '4';

...并避免迭代指针,方法如下:

*(p + 3) = '4';

其他几点说明:

  • 虽然常见的文体练习,但不需要将malloc()的返回值转换为(char *)。 C语言保证void *类型的转换和对齐。

  • 始终检查malloc()的返回值。如果堆分配失败(即你的内存不足),它将为NULL,此时你的程序应退出。

  • 根据实现,malloc()分配的内存区域在某些情况下可能包含陈旧垃圾。分配后将其归零是一个好主意:

    memset(num, 0, 100);
    
  • 永远不要忘记free()你的堆!在这种情况下,程序将退出,操作系统将清理你的垃圾,但如果你没有养成这种习惯,你很快就会有内存泄漏。

所以,这是“最佳实践”版本:

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

int     main(void) {
        char    *num, *p;

        /*
         * Don't take 1-byte chars for granted - good habit to get into.
         */

        num = malloc(sizeof(char) * 100);

        if(num == NULL)
                exit(1);

        memset(num, 0, sizeof(char) * 100);

        p = num;

        strncpy(num, "123056", 100 - 1);

        *(p + 3) = '4';

        printf("%s\n", num);

        free(num);

        return 0;
}

答案 1 :(得分:12)

该代码不起作用,仅仅因为行:

num = "123056";

更改num以指向远离已分配的内存(并且p仍然指向该内存,因此它们不再是相同的位置)到最可能的只读内存。您不能更改属于字符串文字的内存,它是未定义的行为。

您需要以下内容:

#include <stdio.h>
#include <stdlib.h>
int main (void) {
    char *num = malloc (100); // do not cast malloc return value.
    char *p = num;

    strcpy (num, "123056");   // populate existing block with string.

    p = p + 3;                // set pointer to where '0' is.
    *p = '4';                 // and change it to '4'.

    printf ("%s\n", num );    // output it.

    return 0;
}

答案 2 :(得分:1)

除了其他人指出的* p问题外,您还有内存使用问题。你有一个100字节的缓冲区,内容未知。你有另一个7字节的缓冲区,包含字符串“123056”和一个空终止符。你这样做了:

  1. num设置为指向100字节缓冲区
  2. p设置为指向num;即,它指向100字节缓冲区
  3. 你将num重置为指向7字节缓冲区; p仍然指向100字节缓冲区
  4. 使用p修改100字节缓冲区
  5. 然后使用num打印出7字节缓冲区
  6. 因此,您不打印正在修改的缓冲区。

答案 3 :(得分:0)

只需使用*p = '4'; ...!

答案 4 :(得分:0)

嗯,你知道p是指针类型。它存储char'0'的地址。如果为p赋值'4'。它将以'4'作为地址。但是,地址'4'是非法的。您可以使用'*'运算符来获取存储在p中的地址的值。