C言語における「char s[]」と「char *s」の違いとは?メモリ配置と書き換え可否を解説
C言語では、文字列を扱う際に「char s[]」のような配列形式と「char *s」のようなポインタ形式の2つの宣言方法がよく使われます。一見似ているこの2つですが、実際には重要な違いがいくつか存在します。本記事では、その違いをメモリ配置や動作の観点から詳しく解説します。
配列とポインタの基本的な違い
まず大前提として、「s[]」は配列であり、「*s」はポインタであるという点が異なります。
例えば、以下の2つの宣言を比較してみましょう。
- char s[20]
- char *s
この状態でsizeof()を使ってサイズを確認すると、前者は「20」、後者は「4」という結果になります。
前者が20になるのは、20バイト分のデータ領域が確保されていることを示しているためです。一方、後者が4になるのは、ポインタ変数1つ分のサイズ(32ビット環境では4バイト)を表しているためです。
メモリ上の配置の違い
配列形式で宣言した場合、文字列全体がスタック領域に格納されます。
一方、ポインタ形式で宣言した場合、ポインタ変数自体はスタック領域に格納されますが、文字列の実体(リテラル)はコード領域(読み取り専用セクション)に配置されます。
そして最も重要な違いは、ポインタ形式の文字列は編集(書き換え)ができないという点です。つまり、ポインタが指し示す文字列リテラルは読み取り専用となっています。対して、配列形式で宣言した文字列は自由に編集することが可能です。
配列形式の文字列を編集する例
以下のコードでは、配列形式の文字列の6番目の文字を書き換えています。
#include<stdio.h>
main() {
char s[] = "Hello World";
s[6] = 'x'; // 6番目の文字を書き換え
printf("%s", s);
}
出力結果
Hello xorld
このように、配列形式の場合は文字の書き換えが成功します。
ポインタ形式の文字列を編集する例
次に、ポインタ形式の文字列に対して同じ操作を試みてみます。
#include<stdio.h>
main() {
char *s = "Hello World";
s[6] = 'x'; // 6番目の文字を書き換え
printf("%s", s);
}
出力結果
Segmentation Fault
ポインタ形式の場合、読み取り専用領域にある文字列リテラルを書き換えようとするため、実行時にセグメンテーションフォルトが発生し、プログラムが異常終了します。
まとめ
- char s[](配列):文字列全体がスタックに格納され、内容の書き換えが可能
- char *s(ポインタ):ポインタ変数はスタックに、文字列の実体は読み取り専用領域に格納され、書き換え不可
文字列を後から変更する必要がある場合は配列形式を、変更しない読み取り専用の文字列であればポインタ形式を選ぶとよいでしょう。用途に応じて適切な宣言方法を使い分けることで、安全で効率的なプログラムを書くことができます。
-
C#と.NETの違いをわかりやすく解説!言語とフレームワークの関係
C#と.NETの基本的な違いC#(シーシャープ)はマイクロソフトが開発したプログラミング言語であり、一方の.NET(ドットネット)はアプリケーション開発を支援するフレームワークです。この2つは密接な関係にありますが、それぞれの役割はまったく異なります。.NETの中核となる「共通言語ランタイム(CLR)」.NETには「共通言語ランタイム(CLR:Common Language Runtime)」と呼ばれる仮想的な実行環境が組み込まれています。CLRはメモリ管理、例外処理、セキュリティなどを担当し、.NET上で動作するすべてのアプリケーションの土台となる重要なコンポーネントです。C#だけじゃない!
-
GoとJavaの違いを徹底比較!特徴と使い分けのポイント
プログラミング言語を選ぶ際、「Go」と「Java」のどちらを採用すべきか迷う開発者は少なくありません。どちらもGoogleや企業システムで広く使われる人気言語ですが、設計思想や言語仕様には大きな違いがあります。本記事では、それぞれの言語の特徴を解説したうえで、両者の主な違いを比較表を使ってわかりやすく整理します。 GoとはGoはGoogleが開発した手続き型(プロシージャル)プログラミング言語です。プログラムはパッケージ単位で構成され、シンプルで読みやすいコード記述を重視した設計になっています。動的言語に近い柔軟なパターンを取り入れつつ、静的型付けによる安全性も兼ね備えています。また、軽量スレ