2009-06-03 57 views
5

使用c风格的字符串时,如何将字符分配给字符指针指向的内存地址?例如,在下面的示例中,我想将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; 
} 
+0

的可能的复制[为什么写有“字符\ * S”,而不是“char形式\ [\]”初始化字符串时,我得到一个分段错误? ](http://stackoverflow.com/questions/164194/why-do-i-get-a-segmentation-fault-when-writing-to-a-string-initialized-with-cha) – jww 2016-10-20 11:07:51

回答

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; 
} 
0

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

+0

取消引用它没有工作。字符串'num'是不可变的吗?我在Linux上用cc编译。 – 2009-06-03 05:37:54

+0

这是错误的;它应该是'4',而不是4. – 2009-06-03 05:46:11

+0

是的,字符串文字可能被分配在标记为只读的内存中,并且任何尝试写入它都会导致运行时错误。 – sharptooth 2009-06-03 05:47:28

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'; 

...,避免迭代指针,通过deferencing如下:

*(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

感谢您的好记忆管理技巧。这些提示适用于来自自动垃圾收集语言的人! – 2009-06-03 17:47:26

0

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

1

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

  1. NUM被设置为指向100字节的缓冲区
  2. p被设置为指向为num;即它指向100字节缓冲区
  3. 您将num重置为指向7字节缓冲区; p被仍然指向100字节的缓冲区
  4. 您使用p来修改100字节的缓冲区
  5. 然后使用NUM打印出7字节的缓冲区

所以你不打印相同缓冲你正在修改。

相关问题