C언어 기초 질문입니다

jmj0714의 이미지

올해 입학한 대학 새내기 입니다.
전공시간에 포인터와 동적할당에 대해 배우고있는데 궁금증이 생겨 질문드리러 왔습니다.
현재 만들고 싶은 것은 입력값에 따라 크기가 달라지는 배열입니다.
질문 드리겠습니다.
1) int *num = (int*)malloc(n)의 뜻은 n바이트 만큼의 메모리를 할당하고 그 시작 주소를 num이라는 포인터 변수에 int형 포인터 값으로 반환한다는 뜻이라 알고있습니다.
그렇다면 사용자가 4를 눌렀을 때 4바이트 만큼의 메모리가 할당 되고
이에 따라 4개의 int값을 받아야하는 num 배열은 터져야 한다 생각했는데, 배열에 값이 잘 들어갑니다.
본디 예제에는 뒤에 n*sizeof(int)이런 식으로 int값의 크기에 맞게 할당을 하는데.. 저 코드는 어째서 작동하는지 의문입니다. 배열이 왜 안터지는지 설맹해주시면 정말 감사드리겠습니다.

2) *num은 포인터 배열인 것으로 알고있습니다. 그렇다면 scanf를 통해 배열의 값을 넣을때 &num[i]으로 포인터 배열의 주소에 값을 넣는 것이 아닌 num[i]로 배열이 이미 가지고 있는 주소 값에 초기화 하는 것이 맞다 생각했습니다. 헌데 오류가 발생합니다. 이에 대한 설명 부탁드립니다

요약
-> sizeof(int)*n으로 메모리를 적절히 할당하지 않고 n만큼만 할당했는데 어쨰 작동하나?
-> 포인터 배열 num을 초기화 하는데 왜 앞에 &를 붙이나?

자세히 설명해주시면 정말 감사드리겠습니다.

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
 
int main() {
	int n;
	scanf_s("%d", &n);
	int *num = (int*)malloc(n); 
	for (int i = 0; i < n; i++) {
	scanf_s("%d", &num[i]);
	}
 
	for (int i = 0; i < n; i++) {
		printf("배열의 값은 %d 이다\n", num[i]);
	}
	printf("%d\n", _msize(num));
	return 0;
}
익명 사용자의 이미지

1번 질문은 숫제 "내가 무단횡단/신호위반/과속운전을 해봤는데 사고도 안 나고 무사하더라, 왜 그러는지 설명해 줄 수 있겠느냐" 하는 질문이나 마찬가집니다.

그야 그럴 수 있죠. 운이 엄청 좋았다던가, 모처럼 그 때 다른 차가 없었다던가.

제시된 프로그램도 마찬가지입니다. 상황이 너무 단순해서 뭔가 눈에 띄는 문제가 나타나기 전에 프로그램이 종료됐을 뿐이죠.

자세한 분석을 시도해 볼 수야 있겠지만 그건 왜 그 시간대에 주변에 다른 차가 없었는지 알아보는 일만큼이나 별로 유익할 것 같지는 않네요.

FYI. C언어의 세계엔 교통경찰이 없으니 알아서 안전운전하는 편이 좋습니다. 사고 나면 누굴 탓하겠어요?

2번 질문은 답변 달기 훨씬 번거로운데 나중에 시간 나면 (그리고 다른 분이 먼저 답변 안 달면) 써 보겠습니다.

pynoos의 이미지

1.
4 byte를 받아서 그 이상을 접근하는데 왜 문제가 발생하지 않느냐죠.
코드는 그럴지라도 프로세스는 접근 가능한 메모리였기 때문에 문제가 발생하지 않는 것입니다.
때로는 코드의 엄밀성과 구현체의 느슨함 사이에서 버그가 존재합니다.

2.
scanf_s("%d", &num[i]);
이렇게 하는 것이나
scanf_s("%d", num+i);
이렇게 하는 것이나 같은 값을 scanf_s가 필요로 하는 포인터 인자로 넘기게 되죠.
잘 보면 보이실겁니다.

심지어
scanf_s("%d", i + num);
도 해보세요.

jmj0714의 이미지

배열 포인터와 포인터 배열의 차이였군요. 감사합니다!

bushi의 이미지

num[i] 는 i[num] 으로 써도 됩니다.
(num + i) 과 ( i + num ) 의 관계와 같거든요.

cinsk의 이미지

Quote:

이에 따라 4개의 int값을 받아야하는 num 배열은 터져야 한다 생각했는데, 배열에 값이 잘 들어갑니다.

malloc()이 내부적으로 어떻게 구현되어 있느냐에 따라 달라질 수 있는데, 대부분 malloc()은 OS에 큰 메모리 덩어리를 (segment) 요청하고, 그걸 (사용자가 요청한 만큼) 나누어서 메모리를 제공합니다.

프로세스가 죽는 것은 대부분 segmentation fault (SIGSEGV) 때문이고, 이 segmentation fault는, 위에서 할당한 큰 메모리 덩어리 범위를 벗어날 경우에 발생합니다. 따라서 조금 더 overwrite 됐다고 해서 바로 프로그램이 죽지는 않음. (물론 프로그램의 다른 변수가 덮어써 졌을 가능성이 높기 때문에 프로그램이 비정상적으로 동작할 가능성이 큼)

아래는 Linux/Unix 호환 환경일 경우로 한정함. scanf_s()를 쓴 것을 보니 Windows 환경인 것 같지만..

만약, 정말로 바로 죽게 만들고 싶다면, duma 같은 debugging library를 쓰면 됨.

포인터 연산을 잘못해서 alignement를 어겼을 경우, SIGSEGV 대신 SIGBUS가 발생할 수도 있음.

드물게, 포인터 연산을 잘못해서 stack을 덮어썼을 경우, stack return address가 파괴되어 SIGILL이 발생할 수도 있음

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.