1. 程式人生 > >C語言字串、指標和記憶體問題總結

C語言字串、指標和記憶體問題總結

字串:

字串變數是字串的首地址,直到'\0'為止

字串的表示方式:1  字面值”abc”(字串常量)

                              2  char *表示

                              3  char s[n]表示

 字串的操作 

                              

字串的賦值

   =  改的是地址  strcpy()改的是值   

   char *s1=”abc”  通過 = 賦值操作

   這一句可分解為三部分:

   a 宣告;

   b 在只讀常量區申請地址存放“abc”;

   c 賦值 

   char s2[4]=”abc”; 

   a 陣列可以看作是常指標,不能改指向; 

   b 表示把“abc” 只讀常量區內

容賦值到陣列 

     等號 = 右邊“abc”在只讀常量區

   

   strcpy(s1,"123"); 通過 strcpy() 賦值操作

   

**********************************************

char* s1 = "abc";  

char s2[4] = "abc"; 

s1 = "123";

//strcpy(s1,"123");  //error 只讀區的內容不可以更改

//s2 = "123";    //error 

常指標不能改地址,陣列名簡單看作常指標不可改變地址,不能做自加自減操作 

char* s3 = malloc(4);

//s3 = "abc";    //error s3 

指向了只讀區,堆區記憶體丟了 ,導致記憶體洩露

**********************************************

字串的比較   

  == 比地址    strcmp()  比值

 在只讀常量區中  公用相同值的字串    字串值相同的只有一份     相同值的字符串地址也相同     

 

  char* s4 = "123"; char* s5 = "123";           //s4 和 s5都在只讀儲存區

  char s6[4] = "123"; char s7[4] = "123";     // s6 和 s7都是在棧區

  printf("%d\n",s4 == s5);                                //1 比較的是地址  只讀儲存區中,相同值得字串地址也相同 

  printf("%d\n",strcmp(s4,s5)==0);                   //1 比較的是值

  printf("%d\n",s7 == s6);                                 //0 比較的是地址

  printf("%d\n",strcmp(s6,s7)==0);                   

//1 

  比較的是值

字串的拼接   比如拼接檔案路徑和檔名

  char* name = "dsanmux"; 

  char* path = "/home/user"; 

  char buf[50] = { };            //使用過程中先進行初始化

  sprintf(buf,"%s/%s",path,name);  //sprintf 用於字串拼接  (字串拼接方法之一)

  //strcpy(buf,path);  //strcpy和strcat連用完成字串拼接(字串拼接方法二) 

  //strcat(buf,"/"); 

  //strcat(buf,name); 

  printf("buf=%s\n",buf); 

用指標操作字串  比如拆分字串

 方法一

 char* message = "dsanmux,25"; 

 char mname[20] = { }; 

 char age[10] = { }; 

 int i; 

 for(i=0;*(message+i)!=',';i++); 

 strncpy(mname,message,i); 

 strcpy(age,message+i+1); 


 方法二

 

 int flag = 1; //1代表,之前  遇到,改為0  ;定義一個變數進行狀態判斷通過給定flag = 1和flag = 0的變化來確定某一個狀態的變化,程式中常用 

 int i=0,pos; 

 while(*message)

{     

   if(flag)

   { 

       if(*message==',')

      { 

            flag = 0; 

            pos = i; 

            i++; 

            message++; 

            continue; 

      } 

      mname[i] = *message; 

    }

    else

   { 

         age[i-pos-1] = *message; 

    } 

   i++; 

   message++; 

printf("mname=%s:age=%s\n",mname,age); 


字串的長度和容量  

 長度:strlen()是資料有多少 

 容量:是sizeof()是 最大能放多少個 ;

 

 char buf1[100] = { }; 

 strcpy(buf1,"123"); 

 printf("length=%d,size=%d\n",strlen(buf1), sizeof(buf1)); 

字串和int/double之間轉換:

 //sprintf()  sscanf() 

  int a1; 

  char buf2[10] = "123"; 

  sscanf(buf2,"%d",&a1);//字串->int 

  printf("a1=%d\n",a1); 

  char buf3[10] = { }; 

  sprintf(buf3,"%d",a1); 

  printf("buf3=%s\n",buf3); 

指標:

指標是地址
指標變數是變數,是用於存放地址(指標)的變數


記憶體:

1.函式形參位於棧區,函式gettingspace(str);執行完畢形參將自動釋放,從而導致指向(char*)malloc(100);指標釋放導致記憶體洩漏

void gettingspace(char *p_addr)

{

      p_addr = (char*)malloc(100);

}

void test(void)

{

    char  *str = NULL;

    gettingspace(str);

     strcpy(str,"dsanmux");

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

}

char* gettingspace(void)

{

      char* p_addr = (char*)malloc(100);

     return  

p_addr

}

void test(void)

{

    char  *str = NULL;

    str = gettingspace();

     strcpy(str,"dsanmux");

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

}

返回指向堆記憶體的指標是可以的

程式在執行的時候用 malloc 申請任意多少的記憶體,程式設計師自己負責在何時用 free釋放記憶體。動態記憶體的生存期由程式設計師自己決定,使用非常靈活。


2.返回值返回區域性變數地址,gettingspace()執行完畢,棧記憶體釋放,str指向不存在的記憶體,

如果函式的返回值非要是一個區域性變數的地址,那麼該區域性變數一定要申明為static型別

void *gettingspace(void)

{

      char p_addr[] = "dsanmux";   // static char p_addr[] = "dsanmux";   

     return p_addr;

}

void test(void)

{

    char  *str = NULL;

    str = gettingspace();

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

}

3 .函式形參位於棧區,函式gettingspace(str,100);執行完畢形參將自動釋放,從而導致指向(char*)malloc(100);指標釋放導致記憶體洩漏

void gettingspace(char **p_addr,int num)

{

      *p_addr = (char*)malloc(100);

}

void test(void)

{

    char  *str = NULL;

    gettingspace(&str,100);

     strcpy(str,"dsanmux");

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

}

4.

void test(void)

{

    char  *str = 

(char*)malloc(100);

    gettingspace(str);

    strcpy(str,"dsanmux");

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

}

5.

char *gettingspace() 


    char *p="dsanmux"; 
    return p; 

int main() 

    char *str; 
    str=returnStr(); 
    printf("%s\n", str); 
    return 0; 
}

因為"dsanmux"是一個字串常量,存放在只讀資料段,把該字串常量存放的只讀資料段的首地址賦值給了指標,所以returnStr函式退出時,該該字串常量所在記憶體不會被回收,故能夠通過指標順利無誤的訪問。

6.陣列是不能作為函式的返回值的,原因是編譯器把陣列名認為是區域性變數(陣列)的地址。返回一個數組一般用返回指向這個陣列的指標代替,而且這個指標不能指向一個自動陣列,因為函式結束後自動陣列被拋棄,但可以返回一個指向靜態區域性陣列的指標,因為靜態儲存期是從物件定義到程式結束的。

int* gettingspace( void )
{
    static int a[10];
    ........
    return a;


函式是可以返回區域性變數的。 區域性變數的作用域只在函式內部,在函式返回後,區域性變數的記憶體已經釋放了。因此,如果函式返回的是區域性變數的值,不涉及地址,程式不會出錯。

但是如果返回的是區域性變數的地址(指標)的話,程式執行後會出錯。

因為函式只是把指標複製後返回了,但是指標指向的內容已經被釋放了,這樣指標指向的內容就是不可預料的內容,呼叫就會出錯。

準確的來說,函式不能通過返回指向棧記憶體的指標(注意這裡指的是棧,返回指向堆記憶體的指標是可以的)