Can someone tell me what exactly happens here?

This is a discussion on Can someone tell me what exactly happens here? within the C Programming forums, part of the General Programming Boards category; I did this instinctively and it seemed to work but I'd like to know what really happens here. Code: char ...

  1. #1
    Registered User
    Join Date
    Jan 2005
    Posts
    204

    Can someone tell me what exactly happens here?

    I did this instinctively and it seemed to work but I'd like to know what really happens here.
    Code:
    char foo[14] = {'\0'};
    Will all elements of foo be set to '\0' or just the first one and the others will be 0? Thanks

  2. #2
    Super Moderator
    Join Date
    Sep 2001
    Posts
    4,913
    I believe 14 characters are allocated, and the first one is set to a null character - the rest will be random (just whatever was left in memory from the last time it was used. However - I've never seen this before - and not having a cop of the standard - this may be undefined behavior.

  3. #3
    FOX
    Join Date
    May 2005
    Posts
    188
    Isn't it just another way of writing
    Code:
    char foo[14] = "";
    In the same way that char bar[10] = "Hello" can be replaced with
    Code:
    char bar[10] = {'H', 'e', 'l', 'l', 'o', '\0'};
    Last edited by ^xor; 06-15-2005 at 05:35 PM.

  4. #4
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by sean_mackrory
    I believe 14 characters are allocated, and the first one is set to a null character - the rest will be random (just whatever was left in memory from the last time it was used. However - I've never seen this before - and not having a cop of the standard - this may be undefined behavior.
    You were close, but incorrect. Any elements you initialize will have their initialized value. All remaining elements will be zero filled. (That is to say, set to zero.) It is defined in the standard.


    Quzah.
    Hope is the first step on the road to disappointment.

  5. #5
    Registered User
    Join Date
    Jan 2005
    Posts
    181
    well, it looks like the string is fully filled with NULL. consider the following programe

    Code:
    #include<stdio.h>
    
    int main()
    {
        char foo[5]={'\0'};
        int i;
        
        for(i=0;i<5;i++)
            printf("%d",foo[i]);    /* just to find out what it actually prints  - expected ' 0' -
                                                                        ASCII value of NULL
        getchar();
        return 0;
    }
    
    my output
    00000
    - s.s.harish

  6. #6
    Registered User
    Join Date
    Apr 2005
    Posts
    134
    Its a way to define a 0 length string.

    Code:
    #include <stdio.h>
    #include <string.h>
    
    int main(int argc, char *argv[])
    {
    	char buff[5] = {'\0'};
    
            printf("Buff length: %d\n", strlen(buff));
    
    	return 0;
    }
    My output:
    $ ./test1.exe

    Buff length: 0

  7. #7
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,006
    Code:
    printf("Buff length: %d\n", strlen(buff));
    I'm not sure if I've nitpicked in a while, but lest anyone be curious why I choose to use this form...
    Code:
    printf("strlen(buff) = %lu\n", (long unsigned)strlen(buff));
    ...strlen returns a size_t, which is an unsigned integral type. Since %d is for signed integers, it is certainly not the best pick. One could choose %u because on a particular platform a size_t may be implented as an alias for an unsigned int. But I believe the safest C90 way to do it is to explicitly cast the value returned by strlen, or any other size_t value, to an unsigned long and use a corresponding %lu specifier. I believe C99 provides a z length modifier to handle a size_t.
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  8. #8
    Registered User
    Join Date
    Jan 2005
    Posts
    204
    Hum, ok. Thanks a lot.

    Now I was trying to do this
    Code:
    #include <string.h>
    
    char foo[14];
    memset(foo, '\0', sizeof(foo));
    which seems correct to me but Visual C++ is giving me three errors:
    Code:
    c:\Documents and Settings\caduardo21\My Documents\Visual Studio Projects\forum3\forum3.cpp(56): error C2501: 'memset' : missing storage-class or type specifiers
    
    c:\Documents and Settings\caduardo21\My Documents\Visual Studio Projects\forum3\forum3.cpp(56): error C2365: 'memset' : redefinition; previous definition was a 'function'
    
    c:\Documents and Settings\caduardo21\My Documents\Visual Studio Projects\forum3\forum3.cpp(56): error C2078: too many initializers
    What am I doing wrong? Thanks.

  9. #9
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Is that all of the code? Try this:
    Code:
    #include <string.h>
    int main( void )
    {
        char foo[10] = {0};
    
        memset( foo, '\0', 10 );
    
        return 0;
    }
    Same errors? Should be no errors or warnings.


    Quzah.
    Hope is the first step on the road to disappointment.

  10. #10
    Registered User
    Join Date
    Jan 2005
    Posts
    204
    It didn't work. No, that is not the whole code. I didn't post the whole thing because it's in portuguese. Unless you don't mind...

  11. #11
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    What didn't work? Your code or mine? Mine works just fine. Do you get errors compiling my code? If so, what are they?

    Also, if it's not some huge project, sure go ahead and post yours.


    Quzah.
    Hope is the first step on the road to disappointment.

  12. #12
    Registered User
    Join Date
    Jan 2005
    Posts
    204
    Your code compiles just fine without errors or warnings. Here's mine...
    Code:
    /* 
    // Objetivo do programa:
    // ---------------------
    // Programa em linguagem C que permite as seguintes opções: 
    // (a) Abrir semestre
    // (b) Incluir disciplina
    // (c) Informar nota ou freqüência 
    // (d) Finalizar semestre
    // (f) Fechar semestre
    // (g) Sair do programa
    //
    //
    // Componentes do grupo:
    // ---------------------
    // Nome:
    // Nome:
    //
    //
    // Data e hora da última atualização do texto do programa:
    */
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <windows.h>
    
    void mostrar_menu(void);
    int escolha_valida(char);
    int processar_escolha(char);
    void limpar_buffer(void);
    void tirar_newline(char[]);
    void abrir_semestre(void);
    void adicionar_linha(char[]);
    void clrscr(void);
    void fechar_semestre(void);
    
    /*
    // Esta struct será usada na lista encadeada
    // que vai armazenar todas as linhas lidas do
    // arquivo do semestre. Abaixo dela está a
    // declaração do primeiro nó que será usado
    // para marcarmos o começo da lista.
    */
    struct node {
    	char linha[100];
    	struct node *proximo;
    };
    struct node *primeiro = NULL;
    
    /*
    // Este vetor armazenará o nome do arquivo do
    // semestre que o usuário quer abrir.
    */
    char nome_do_arquivo[14] = {0};
    memset(nome_do_arquivo, '\0', sizeof(nome_do_arquivo));
    
    int main(void)
    {
    	char escolha;
    
    	/*
    	// Enquanto a opção escolhida pelo
    	// usuário não for igual à letra g...
    	*/
    	do {
    		do {
    			mostrar_menu();
    			printf("> ");
    			escolha = getchar();
    			limpar_buffer();
    			escolha = tolower(escolha);
    		} while(escolha_valida(escolha) == 0);
    	
    	} while(processar_escolha(escolha) != 0);
    
    	return 0;
    }
    
    /*
    // Esta função simplismente limpará
    // a tela e depois mostrará o menu
    // do programa.
    */
    void mostrar_menu(void)
    {
    	clrscr();
    	printf("(a) Abrir semestre\n");
    	printf("(b) Incluir disciplina\n");
    	printf("(c) Informar nota ou frequencia\n");
    	printf("(d) Finalizar semestre\n");
    	printf("(f) Fechar semestre\n");
    	printf("(g) Sair do programa\n");
    }
    
    /*
    // Esta função faz com que o usuário
    // escolha uma das opções que estão
    // no menu do programa e nada mais.
    // Ela retorna 0 se a opção do usuário
    // é inválida e 1 caso contrário.
    */
    int escolha_valida(char escolha)
    {
    	if((escolha < 'a' || escolha > 'd') && (escolha < 'f' || escolha > 'g')) {
    		printf("Comando desconhecido\n");
    		limpar_buffer();
    		return 0;
    	}
    
    	return 1;
    }
    
    /*
    // Esta função limpa o buffer do teclado.
    // Caso o buffer já esteja limpo, o usuário
    // terá que apertar enter para continuar com
    // a execução do programa.
    */
    void limpar_buffer(void)
    {
    	int c;
    
    	while((c = getchar()) != '\n' && c != EOF)
    		;
    }
    
    /*
    // Esta função recebe a opção que o usuário
    // escolheu (depois que ela passou pelo teste
    // de validade) e chama a função que executa
    // a tarefa escolhida de acordo. Ela sempre
    // retornará 1 a não ser que a opção escolhida
    // foi a opção g (sair do programa).
    */
    int processar_escolha(char escolha)
    {
    	switch(escolha) {
    		case 'a':
    			abrir_semestre();
    			return 1;
    
    		case 'b':
    			printf("Incluir disciplina");
    			getchar();
    			return 1;
    
    		case 'c':
    			printf("Informar nota ou frequencia\n");
    			getchar();
    			return 1;
    
    		case 'd':
    			printf("Finalizar semestre\n");
    			getchar();
    			return 1;
    
    		case 'f':
    			clrscr();
    			printf("Fechar semestre\n");
    			return 1;
    
    		default:
    			return 0;
    	}
    }
    
    /*
    // Quando lemos alguma coisa com a função
    // fgets(), um \n é adicionado no vetor
    // que recebe os caracteres lidos. Se um
    // \n não é encontrado, isso significa que
    // nem todos os caracteres digitados pelo
    // usuário foram adicionados no vetor e
    // que existe "sujeira" no buffer do teclado.
    // Esta função retira o \n do vetor ou limpa
    // o buffer do teclado de acordo com a situação.
    */
    void tirar_newline(char linha[])
    {
    	char *ptr;
    
    	if((ptr = strchr(linha, '\n')) != NULL)
    		*ptr = '\0';
    
    	else
    		limpar_buffer();
    }
    
    /*
    // Esta função recebe a linha que foi lida
    // do arquivo do semestre e a adiciona na
    // lista encadeada.
    */
    void adicionar_linha(char linha[])
    {
    	struct node *novo;
    	struct node *guia;
    
    	novo = (struct node*)malloc(1 * sizeof(*novo));
    	if(novo == NULL) {
    		printf("\nmalloc() retornou NULL!\n");
    		exit(1);
    	}
    
    	novo->proximo = NULL;
    	strcpy(novo->linha, linha);
    
    	if(primeiro == NULL)
    		primeiro = novo;
    
    	else {
    		guia = primeiro;
    		while(guia->proximo != NULL)
    			guia = guia->proximo;
    
    		guia->proximo = novo;
    	}
    }
    
    /*
    // Esta função simplismente limpa a tela
    // utilizando funções da API do Windows.
    // Infelizmente ela não funcionará no Linux.
    */
    void clrscr(void)
    {
        HANDLE handle;
    	COORD coord = {0, 0};
    	DWORD tamanho_do_console;
    	CONSOLE_SCREEN_BUFFER_INFO csbi;
        
    	handle = GetStdHandle(STD_OUTPUT_HANDLE);
    	GetConsoleScreenBufferInfo(handle, &csbi);
    	tamanho_do_console = csbi.dwSize.X * csbi.dwSize.Y;
            FillConsoleOutputCharacter(handle, ' ', tamanho_do_console, coord, NULL);
    	SetConsoleCursorPosition(handle, coord);
    }
    
    /* 
    // Esta função recebe o semestre que o usuário quer abrir.
    // Caso o arquivo do semestre já exista, armazenamos todas
    // as linhas do arquivo em nossa lista encadeada e depois
    // fechamos o arquivo. Caso contrário, só criamos um arquivo
    // e logo em seguida o fechamos. Eu podia passar o ponteiro
    // que aponta para o arquivo para a função fechar_semestre()
    // mas achei melhor fazer com que cada função controle seus
    // própios ponteiros para evitar possíveis confusões.
    */
    void abrir_semestre(void)
    {
    	char linha[100];
    	char semestre[7];
    	FILE *arquivo_do_semestre;
    
    	clrscr();
    	printf("Abrir semestre\n--------------\n");
    	printf("Semestre: ");
    	fgets(semestre, sizeof(semestre), stdin);
    	tirar_newline(semestre);
    
    	strcpy(nome_do_arquivo, "sem");
    	strcat(nome_do_arquivo, semestre);
    	strcat(nome_do_arquivo, ".txt");
    
    	arquivo_do_semestre = fopen(nome_do_arquivo, "r");
    	if(arquivo_do_semestre == NULL) {
    		arquivo_do_semestre = fopen(nome_do_arquivo, "w");
    
    		if(arquivo_do_semestre == NULL) {
    			printf("\n%s nao pode ser criado.");
    			exit(1);
    		}
    
    		fclose(arquivo_do_semestre);
    	}
    
    	else {
    		while(fgets(linha, sizeof(linha), arquivo_do_semestre) != NULL)
    			adicionar_linha(linha);
    		fclose(arquivo_do_semestre);
    
    		//fechar_semestre();
    	}
    }
    
    /*void fechar_semestre(void)
    {
    	FILE *arquivo_do_semestre;
    
    	/*
    	// nome_do_arquivo é o vetor de caracteres que
    	// foi declarado globalmente no início do programa.
    	/
    	arquivo_do_semestre = fopen(nome_do_arquivo, "r");*/
    The error "is" on line 56

  13. #13
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,046
    memset() is a function call. It has to be in a function.

    dwk

  14. #14
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,046
    Code:
    /*
    // Este vetor armazenará o nome do arquivo do
    // semestre que o usuário quer abrir.
    */
    char nome_do_arquivo[14] = {0};
    memset(nome_do_arquivo, '\0', sizeof(nome_do_arquivo));
    
    int main(void)
    {
    	char escolha;
    Change to

    Code:
    /*
    // Este vetor armazenará o nome do arquivo do
    // semestre que o usuário quer abrir.
    */
    char nome_do_arquivo[14] = {0};
    
    int main(void)
    {
    	char escolha;
    
            memset(nome_do_arquivo, '\0', sizeof(nome_do_arquivo));

  15. #15
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    I was thinking that's what was happening. That's why I asked if that's all the code it was. On an aside, the way you're declaring the array, you're already initializing everything to zero, so there's no point in even calling memse.


    Quzah.
    Hope is the first step on the road to disappointment.

Popular pages Recent additions subscribe to a feed

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21