C語言字串、指標和記憶體問題總結
字串:
字串變數是字串的首地址,直到'\0'為止
字串的表示方式:1 字面值”abc”(字串常量)
2 char *表示
3 char s[n]表示
字串的操作 :
1 字串的賦值
= 改的是地址 和 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
指向了只讀區,堆區記憶體丟了 ,導致記憶體洩露
**********************************************
2 字串的比較
== 比地址 和 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
比較的是值
3 字串的拼接 比如拼接檔案路徑和檔名
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);
4 用指標操作字串 比如拆分字串
方法一
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);
5 字串的長度和容量
長度:strlen()是資料有多少 ;
容量:是sizeof()是 最大能放多少個 ;
char buf1[100] = { };
strcpy(buf1,"123");
printf("length=%d,size=%d\n",strlen(buf1), sizeof(buf1));
6 字串和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;
}
函式是可以返回區域性變數的。 區域性變數的作用域只在函式內部,在函式返回後,區域性變數的記憶體已經釋放了。因此,如果函式返回的是區域性變數的值,不涉及地址,程式不會出錯。
但是如果返回的是區域性變數的地址(指標)的話,程式執行後會出錯。
因為函式只是把指標複製後返回了,但是指標指向的內容已經被釋放了,這樣指標指向的內容就是不可預料的內容,呼叫就會出錯。
準確的來說,函式不能通過返回指向棧記憶體的指標(注意這裡指的是棧,返回指向堆記憶體的指標是可以的)。