2011-02-12 3 views
3

저는 C 언어에 대해 상당히 익숙하며 문자열을 참조 할 때 배열과 포인터에 익숙해 져 있습니다. 나는 2 개의 숫자 (정수)의 입력을 요구할 수 있으며, 아무런 문제없이 원하는 숫자 (첫 번째 숫자 또는 두 번째 숫자)를 반환 할 수 있습니다. 그러나 이름을 요청하고이를 반환하려고 시도 할 때 이름을 입력하고 이유를 모르면 프로그램이 중단됩니다.포인터와 malloc 문제

이론에서는 이름을위한 메모리를 예약 한 다음 두 번째 이름을 포함하도록 메모리를 확장하려고합니다. 왜이 휴식 시간을 설명 할 수 있을까요?

감사합니다.

#include <stdio.h> 
#include <stdlib.h> 



void main() 
{ 
    int NumItems = 0; 

    NumItems += 1; 
    char* NameList = malloc(sizeof(char[10])*NumItems); 
    printf("Please enter name #1: \n"); 
    scanf("%9s", NameList[0]); 
    fpurge(stdin); 

    NumItems += 1; 
    NameList = realloc(NameList,sizeof(char[10])*NumItems); 
    printf("Please enter name #2: \n"); 
    scanf("%9s", NameList[1]); 
    fpurge(stdin); 

    printf("The first name is: %s",NameList[0]); 
    printf("The second name is: %s",NameList[1]); 

    return 0; 

} 
+0

0을 반환하는'void' 함수를 사용할 수 없습니다. 'main()'은 항상 처음에'int'를 반환하도록 선언되어야합니다. –

+0

고마워요 조나단. 나는 그 변화를 만들었다. – Andy

답변

6

내가 당신의 문제가이 코드에 있다고 생각 :

scanf("%9s", NameList[0]); 

문제는 여기에 scanf이 인수 당신이해야 결과를 저장하는 위치로 제공해야한다는 것이다 포인터. 포인터가 아닌 것을 제공하면 scanf은 그것을 마치 마치 메모리를 임의의 위치에 쓰면서 프로그램을 충돌시킵니다.

이 문제를 해결하려면 두 단계가 필요합니다. 먼저 NameList이라는 선언을 변경하여 더 이상 char *이 아닌 것으로 바꿔야합니다. 그 이유는 char *단일 문자열 인 반면 배열 문자열이 필요하기 때문입니다. 이것은 char **으로 정의되며, 배열에 대한 포인터는 char *입니다. 다음과 같이 표시 될 수 있습니다.

char** NameList; 

다음으로 문자열의 저장 공간을 할당해야합니다. 이것은 두 가지 할당을해야하기 때문에 까다 롭고 약간 미묘합니다. 첫째, 당신은 당신이 이렇게 할 수있는 배열 자체를위한 공간을 할당해야이 문자에 대한 포인터의 배열을 할당

NameList = malloc (sizeof(char*) * NumItems); 

하지만 실제로 가리 키도록 그 배열의 포인터를 설정하지 않습니다 유효한 메모리 위치.이 문제를 해결하려면, 당신은 다음이 배열을 통해 반복하고 모든 요소를이 문자열을 저장하기에 충분히 큰 버퍼에 대한 포인터로 설정하는 것이 좋습니다 - 길이 10의 버퍼,이 경우 : 이제

int i; 
for (i = 0; i < NumItems; ++i) 
    NameList[i] = malloc (10); // Space for 10 characters 

, NameList[0]는 문자가 기록되어야하는 버퍼에 char * 포인팅이기 때문에 당신은

scanf("%9s", NameList[0]); 

를 호출 할 수 있습니다.

코드에 대한 주석이 하나 더 있습니다. 한 요소의 배열을 할당 한 다음 나중에 두 요소의 배열에 다시 할당하는 대신 모든 공간을 앞쪽에 할당하는 것을 고려하십시오. 조금 더 명확 해. 또한, 이제는 char *의 버퍼를 다루고 있기 때문에, 각각의 버퍼를 가리 키도록 초기화해야합니다. 증분 할당을 할 경우 새로운 char *을 모두 초기화해야합니다. 어딘가에 버퍼를 가리 키도록 할당하십시오. 이 단계를 한 번에 수행하는 경우 포인터를 설정하고 충돌을 일으키는 것을 잊을 수있는 좋은 기회가 있습니다. 반면에 앞면으로하면 위험이 없습니다.

동적으로 할당 된 메모리를 해제해야하는 경우 역순으로 할당 프로세스를 실행하여 먼저 문자열에 동적으로 할당 된 버퍼를 비운 다음 최상위 버퍼를 해제해야합니다. 예를 들어 : free 재귀 적으로 작동하지 않기 때문에

for (i = 0; i < NumItems; ++i) 
    free (NameList[i]); 
free (NameList); 

이 필요합니다. 할당 한 모든 메모리를 명시 적으로 할당 해제해야합니다. 당신이 하지

참고는 다음과 같이 코드를 작성 : 먼저 최상위 배열을 해제하는 경우 때문에

free (NameList); 
for (i = 0; i < NumItems; ++i) 
    free (NameList[i]); 

이 런타임에 나쁜 것들의 모든 종류의 원인이됩니다, 당신은 반복 시도로 그 내용에 포인터를 비우면 더 이상 소유하지 않은 메모리를 읽을 수 있습니다.

희망이 도움이됩니다.

+0

훌륭한 설명이지만 메모리를 '비우는'방법을 보여주는 코드는 좋을 것입니다. – user470379

+0

@ user470379- 우수합니다. 내가 지금 고칠거야. – templatetypedef

+0

@templatetypedef 큰 설명과 free() 사용을 상기시켜 줘서 고마워. 나는 그것을 약간 다른 코드를 사용하여 작동 시키도록 관리했지만, 당신의 char **가 아마도 정확하고 내 것이 행운을 해결하기 위해 일어 났을 것이라고 생각합니다. 'NumItems + = 1; \t char * NameList [10]; \t NameList [NumItems-1] = malloc (sizeof (char [10]) * NumItems); \t printf ("이름을 입력하십시오 : \ n"); \t scanf ("% 9s", NameList [0]); ' [NumItems-1]을 사용하고 있었기 때문에 처음에는 총 # 개를 모르는 루프에서이 작업을 수행 할 수있었습니다. – Andy

1

NameList 변수는 단일 문자열에 대한 포인터 인 char *입니다. (char *는 단일 문자입니다. char **는 문자열의 배열입니다.)

NameList [1]을 사용하면 실제로 두 번째 문자을 인덱싱합니다. 두 번째 문자열 자체.

는 대신 같은 문자열의 배열, 뭔가를 할당해야합니다

char (*NameList)[10]; 
    NameList = malloc(10*sizeof(char)*NumItems); 

편집 : 일부 컴파일 오류가 수정되었습니다. (Sample code.) sizeof (char)는 항상 필요하지 않음에 유의하십시오. 항상 그렇습니다.

+0

고마워, 나는 그것을 쏜다. 하나의 빠른 편집은 & scanf에 & 연산자를 추가하여 실제로 오류가 발생하지 않도록했지만, 결과에 이름과 첫 번째 이름의 첫 번째 문자가 포함되어 있다고 나와 있습니다. 그래서 두 번째 scanf는 첫 번째 겹침이 첫 번째 겹쳐 씁니다. – Andy

+1

@Eric Pi- 나는 이것에 관해 틀릴 수도 있지만,이 코드는 불법이 아닙니까? 'NameList'는 배열이며 배열에 값을 할당 할 수 없습니다. – templatetypedef

+0

@template : 당신이 옳을 수도 있습니다. 먼저 포인터의 배열을 할당 한 다음 각 문자열을 루프에 할당하는 대답은 거의 확실한 방법입니다. 가능한 최소한의 수정으로 샘플 코드를 외과 적으로 치료하려고했습니다. 지금 컴파일하고 검증 할 것입니다 ... –

1

2 차원 배열의 문자 (모든 요소가 char의 배열 인 배열)가 필요한 경우 잘못된 방식으로 메모리를 할당하고있는 것입니다. 올바른 방법은 다음과 같습니다

int main(){ 

int i; 
int NumItems = 2; 

/* Alocate a variable which every position points to an array of character */ 
char ** NameList = (char **) malloc(sizeof(char *) * NumItems); 

/* For each position, allocate an array of 10 characters */ 
for(i = 0; i < NumItems; i++){ 
    NameList[i] = (char *) malloc(sizeof(char) * 10); 
} 

printf("Please enter name #1: \n"); 
scanf("%s", NameList[0]); 

printf("Please enter name #2: \n"); 
scanf("%s", NameList[1]); 

printf("The first name is: %s",NameList[0]); 
printf("The second name is: %s",NameList[1]); 

/* Free allocated memory. Always a good practice and prevents memory leaks. */ 
for(i = 0; i < NumItems; i++){ 
    free(NameList[i]); 
} 
free(NameList); 

return 0; 

} 
+0

기침'free' 기침 – user470379

+0

정말로 그 질문의 일부가 아니 었나요? 어쨌든 고칠 것입니다. 고마워요. – Piva

+0

감사합니다. 나는 정말로 내 자신의 기억 속에 자유()를 사용하여 타지 않으면 안된다. – Andy

0

또한 단지 스택 공간을 사용하는 대신 malloc를 사용하여 동적으로 힙 공간을 할당 고려 :

#define NumItems 2 
char NameList[NumItems][10]; 

printf("Please enter name #1: \n"); 
scanf("%9s", NameList[0]); 

printf("Please enter name #2: \n"); 
scanf("%9s", NameList[1]); 

printf("The first name is: %s",NameList[0]); 
printf("The second name is: %s",NameList[0]); 

을 일반적으로 동적 크기의 배열에 대한 필요가 없다면, 그것은 일반 배열을 사용하는 것이 훨씬 더 쉽다.