1. 程式人生 > >字元指標的初始化以及程式分析例項

字元指標的初始化以及程式分析例項

      1. 初學者經常被這個問題所困惑: char *p="abc"==>"abc"是一個const char*,為什麼能夠賦值給char *呢?       2. 很多論壇上都可以看到這樣的提問帖,不過這些帖子有的講的是錯誤的,有的雖然是對的,但是講的不細緻,初學者不好理解。對此,我根據我的經驗,以及CSDN上的一些帖子仔細地說一下其中的道理。       3. 按照 C/C++ 標準的描述,"abc" 是 string literal (字元字面量、字元文字量),具有靜態儲存性質,型別是陣列型別,並且不能被改變。注意:"abc" 是一個數組型別的物件,是左值。當然左值可以轉化為右值使用,就像陣列型別的物件可以轉化為指標一樣。
      4. 雖然 "abc" 是陣列型別,但是 C 和 C++ 在型別規定上是有區別的:在 C 中,"abc" 的型別是 char [4];在  C++ 中,其型別是 const char [4]。 由於陣列型別可以轉換為指標型別來使用,所以在 C 和 C++ 中 "abc" 可分別作為 char* 及 const char* 使用。       5. 為了相容c中char *p="abc"這種現象的存在,C++特別允許初始化時const char*到char*的自動轉換。但是這條規則被 C++ 標明為 “Deprecated”,不被推薦使用。       6. 綜上所述,在 C 中:char *p="abc"是完全合乎規則的事情,在 C++ 中:由於有特殊規定,所以這樣也可以。
但在c++中要注意:char *p="abc" 能不能編譯通過要看你使用的編譯器。鑑於大量遺留程式碼的存在,大部分編譯器允許其通過,或者給個警告。當然,程式設計師自己必須保證絕不去修改其值:
A.   程式設計師不應該在程式碼中出現*p='A'這樣的語句。這是當初約定好了的:編譯器允許char *p="abc"通過,而程式設計師保證不去修改它。  B.   *p='A'編譯時應該允許通過,因為單就這條語句而言,它完全合法。 
C.   執行時*p='A'能不能通過要看實際的執行環境,包括你使用的作業系統、編譯器、編譯器選項 等等,一句話,其執行結果由不得你,且不應該由你去關心,因為這種行為本身已經違反約定了。
例:當我們修改字串常量型別的指標變數時,編譯器會提示程式出錯的。下面來具體講一講這種型別的錯誤。 程式1:
#include <string.h>
#include <stdio.h>
int main()
{
    //char str[5]="good";
    char *str="good";
    char *strtemp=NULL;
    printf("The string befor reversal: %s\n",str);
    strtemp=strrev(str);   
    printf("The string strtemp reversed is: %s\n",strtemp);

    return 0;
}

當我們用VC++編譯時,會終止程式,並且彈出這樣的提示資訊:

但是這樣的提示還是不夠清楚,我們可以換個編譯器, 當我們用VS2013編譯執行下面的程式時: 程式2:
// ConsoleApplication2.cpp : 定義控制檯應用程式的入口點。
//
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
int _tmain(int argc, _TCHAR* argv[])
{
	char *forward = "string";
	printf("Before strrev(): %s\n", forward);
	_strrev(forward);
	printf("After strrev(): %s\n", forward);
	return 0;
}
VS2013會終止程式,並且彈出這樣的提示資訊:
其實在程式中,我們已經修改了字串常量指標,所以編譯器會彈出提示資訊,並且程式不能正常執行。 在程式1中,有這樣幾句程式碼:
    char *str="good";
    char *strtemp=NULL;
    printf("The string befor reversal: %s\n",str);
    strtemp=strrev(str);   
系統函式strrev( )已經修改了字串指標變數str的值,所以程式會出現修改常量的錯誤。 在程式2中:
char *forward = "string";
printf("Before strrev(): %s\n", forward);
_strrev(forward);
printf("After strrev(): %s\n", forward);
這幾句程式碼也是犯了同樣的錯誤。 所以可以將程式1修改如下:
#include <string.h>
#include <stdio.h>
int main()
{
    char str[5]="good";
    //char *str="good";
    char *strtemp=NULL;
    printf("The string befor reversal: %s\n",str);
    strtemp=strrev(str);   
    printf("The string strtemp reversed is: %s\n",strtemp);
    return 0;
}
此程式在VC++6.0的執行結果如下:
此處用字元陣列代替了字串指標常量,而陣列的值是可以修改的。

相關推薦

字元指標初始以及程式分析例項

      1. 初學者經常被這個問題所困惑: char *p="abc"==>"abc"是一個const char*,為什麼能夠賦值給char *呢?       2. 很多論壇上都可以看

C/C++—— 在建構函式中呼叫虛擬函式能實現多型嗎(Vptr指標初始的過程分析

問題引入: 比如:如果我們想在父類的建構函式中呼叫虛擬函式,當定義子類物件的時候,父類的建構函式中的虛擬函式執行的是子類中的函式。 在下面的例子中,定義子類物件的時候,在父類建構函式中的print虛擬函式執行的不是子類中的print函式,而是父類中的prin

關於類的初始以及類的例項一些思考

前言 上一篇我們知道了一個類的生命週期是:載入->驗證->準備->解析->初始化->使用->解除安裝。 當初始化完成以後,一個類所有的類變數(被static修飾的變數)都被賦值。但是未被static修飾的成員變數又是何時被賦值的呢? 一個類何時會被初始化 一個類何時被初始化

Webkit初始以及載入URL過程中各種對象的建立時序以及DOM樹的建立詳情分析

沒有 chrom 本地 .net 時間 詳情 request avi ng-click ? ? ? ? 眾所周知,Webkit須要創建DOM樹。為此它須要創建Web

Java靜態初始例項初始以及構造方法

首先有三個概念需要了解: 一.靜態初始化:是指執行靜態初始化塊裡面的內容。 二.例項初始化:是指執行例項初始化塊裡面的內容。 三.構造方法:一個名稱跟類的名稱一樣的方法,特殊在於不帶返回值。 我們先來看一段程式結果:package com; class Book{

【DWM1000】 code 解密一 工程初始代碼分析

eof associate 回調函數 pre ack 也有 tca use fas Draft ,以後整理 instance_init 函數追下去,絕大多數的代碼都在初始化如下結構體 typedef struct { INST_MODE mode; instan

MySQL初始以及客戶端工具的使用

sock 詳細信息 linux form 關系型 orm ctr create 主機名                       MySQL初始化以及客戶端工具的使用                                             作者:尹正傑 版

Java構造方法、成員變量初始以及靜態成員變量初始三者的先後順序是什麽樣的?

java學習 程序 tar 變量初始化 ref 優先 靜態 上海 優先級 【Java筆試真題】:構造方法、成員變量初始化以及靜態成員變量初始化三者的先後順序是什麽樣的? 【解答】:當類第一次被加載的時候,靜態變量會首先初始化,接著編譯器會把實例變量初始化為默認值,然後執行構

C++ 指標初始要注意的地方

1. 宣告多個指標的時候: int* P1,P2; 如上所示,宣告的是建立一個指標P1和一個int型的變數P2。而不是宣告的兩個指標。 對每個指標變數名,都需要使用一個*。 在C++中,int* 是一種複合型別,是指向int的指標。 2. 可以在宣告語句中初始化指標,但是,在這種情況下,被

求助!結構體的二級指標陣列給一級指標初始遇見的異常

百度也看了很多部落格都沒解決 主要程式碼如下 typedef struct HTNode { int weight; char c;//存這個字元,單個字元,符號都是葉子節點 int code; HTNode *lchild, rchild; }HuffmanTree; /

Mysql 5.7初始以及忘記root密碼解決方法

主要檔案位置     ##沒加粗的路勁都是自己指定的,mysql5.7編譯安裝可看上一篇文章       /usr/local/mysql57/bin/mysql               主服務程式      /etc/my.cnf                 

Java構造方法、成員變數初始以及靜態成員變數初始三者的先後順序是什麼樣的?

【Java筆試真題】:構造方法、成員變數初始化以及靜態成員變數初始化三者的先後順序是什麼樣的? 【解答】: 當類第一次被載入的時候,靜態變數會首先初始化,接著編譯器會把例項變數初始化為預設值,然後執行構造方法。 Java程式的初始化一般遵循以下三個原則(以下三原則優先順序依次遞減): ①

twemproxy0.4原理分析-系統初始過程原理分析

概述 本文介紹twemproxy的系統初始化過程。該過程包括以下幾個方面的內容: 讀取配置檔案,根據配置檔案初始化資料結構 和後臺伺服器建立連線,形成伺服器連線池 初始化事件處理框架,並設定最開始的事件處理函式 建立twemproxy的監聽socket,

1-git的初始以及配置

git的初始化 作用:建立原生代碼倉庫 位置:本臺電腦隨意一資料夾下,不要在根目錄 初始化命令 git init # git本地倉庫初始化 git配置使用者名稱和郵箱 作用:每次c

連結串列的初始以及查詢連結串列中倒數第k個節點的值

package com.xhy.stackandqueue; public class LinkedList { public static class Node { int value; Node next; public Nod

xutils3的初始以及簡單使用

1、依賴xutils3相關依賴包 使用Android studio開發工具對xutils3的依賴有三種方法,一種是新增module,一種是新增本地jar包,一種是直接依賴網上依賴庫中的檔案,前兩種是需要將xutils相關的檔案下載到本地,然後在做一系列的關聯,以及修改,本人

opencv對影象名進行修改、Mat指標初始

參考連結 https://blog.csdn.net/susu_love/article/details/53218628 https://blog.csdn.net/Kelvin_Yan/article/details/48315175?utm_source=blogxgwz1 利用指

ios物件初始以及初始方法

1、所有的類呼叫alloc方法來分配記憶體 2、init方法完成初始化 init方法雖然 可以完成初始化,但是由於它是完成最基本的初始化,因此,物件的所有成員變數依然是0; 一、我們可以重寫初始化方法:init NSObject提供的初始化時最基本的初始化,因此,物件

【重點】內部類初始以及訪問外部類變數

成員內部類可以隨便訪問成員變數, 方法的內部類訪問方法的成員變數,成員變數必須是final型別 package com.xiaozhi.interclazz; class Outer { private int x = 3; class Inner { in

帶有繼承和靜態的類的初始以及載入過程(重要)

package com.google.test; public class BaseClass { public void haha(){ printInit(“haha”