【C】 48_函數設計原則 (完結)

函數設計原則

  • 函數從意義上應該是一個獨立的功能模塊(功能單一)
  • 函數名要在必定程度上反應函數的功能
  • 函數參數名要可以體現參數的意義
  • 儘可能避免在函數中使用全局變量以及局部靜態變量(無狀態函數)

void sc(char* s1, char* s2);
void str_copy(char* str_dest, char* str_src);css


  • 當函數參數不該該在函數體內部被修改時,應該加上 const 聲明
  • 若是參數是指針,且僅做輸入參數,則應加上 const 聲明

void str_copy(char* str_dest, const char* str_src);html


  • 不能省略返回值得類型java

    • 若是函數沒有返回值,那麼應該聲明爲 void 類型
  • 對參數進行有效性檢查編程

    • 對於指針參數的檢查尤其重要
  • 不要返回指向 「棧內存」 的指針數組

    • 棧內存在函數體結束時被自動釋放

  • 函數體的規模要小,儘可能控制在 80 行代碼以內
  • 相同的輸入對應相同的輸出,避免函數帶有 「記憶」 功能
  • 避免函數有過多的參數,參數個數儘可能控制在 4 個之內

  • 有時候不須要返回值,但爲了增長靈活性,如支持鏈式表達,能夠附加返回值
char s[64];
int len = strlen(strcopy(s, "D.T.software"));
  • 函數名與返回值類型在語義上不可衝突,不可有二義性
char c = getchar();    // getchar() 實際返回值類型爲 int

if( EOF == C )
{
    // ...
}

示例分析: 優秀代碼賞析 eclipseUtil.c

/*******************************************************************************
 * Copyright (c) 2000, 2005 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at 
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Kevin Cornell (Rational Software Corporation)
 *******************************************************************************/

/* Eclipse Launcher Utility Methods */

#include "eclipseOS.h"
#include "eclipseCommon.h"
#include "eclipseUtil.h"

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#ifdef _WIN32
#include <direct.h>
#else
#include <unistd.h>
#include <strings.h>
#endif

#define MAX_LINE_LENGTH 256

/* Is the given VM J9 */
int isJ9VM( _TCHAR* vm )
{
    _TCHAR * ch = NULL, *ch2 = NULL;
    int res = 0;
    
    if (vm == NULL)
        return 0;
    
    ch = lastDirSeparator( vm );
    if (isVMLibrary(vm)) {
        /* a library, call it j9 if the parent dir is j9vm */
        if(ch == NULL)
            return 0;
        ch[0] = 0;
        ch2 = lastDirSeparator(vm);
        if(ch2 != NULL) {
            res = (_tcsicmp(ch2 + 1, _T_ECLIPSE("j9vm")) == 0);
        }
        ch[0] = dirSeparator;
        return res;
    } else {
        if (ch == NULL)
            ch = vm;
        else
            ch++;
        return (_tcsicmp( ch, _T_ECLIPSE("j9") ) == 0);
    }
}

int checkProvidedVMType( _TCHAR* vm ) 
{
    _TCHAR* ch = NULL;
    struct _stat stats;
    
    if (vm == NULL) return VM_NOTHING;
    
    if (_tstat(vm, &stats) == 0 && (stats.st_mode & S_IFDIR) != 0) {
        /* directory */
        return VM_DIRECTORY;
    }

    ch = _tcsrchr( vm, _T_ECLIPSE('.') );
    if(ch == NULL)
        return VM_OTHER;
    
#ifdef _WIN32
    if (_tcsicmp(ch, _T_ECLIPSE(".dll")) == 0)
#else
    if ((_tcsicmp(ch, _T_ECLIPSE(".so")) == 0) || (_tcsicmp(ch, _T_ECLIPSE(".jnilib")) == 0) || (_tcsicmp(ch, _T_ECLIPSE(".dylib")) == 0))
#endif
    {
        return VM_LIBRARY;
    }
    
    if (_tcsicmp(ch, _T_ECLIPSE(".ee")) == 0)
        return VM_EE_PROPS;
    
    return VM_OTHER;
}

/*
 * pathList is a pathSeparator separated list of paths, run each through
 * checkPath and recombine the results.
 * New memory is always allocated for the result
 */
_TCHAR * checkPathList( _TCHAR* pathList, _TCHAR* programDir, int reverseOrder) {
    _TCHAR * c1, *c2;
    _TCHAR * checked, *result;
    size_t checkedLength = 0, resultLength = 0;
    size_t bufferLength = _tcslen(pathList);
    
    result = malloc(bufferLength * sizeof(_TCHAR));
    c1 = pathList;
    while (c1 != NULL && *c1 != _T_ECLIPSE('\0'))
    {
        c2 = _tcschr(c1, pathSeparator);
        if (c2 != NULL)
            *c2 = 0;
        
        checked = checkPath(c1, programDir, reverseOrder);
        checkedLength = _tcslen(checked);
        if (resultLength + checkedLength + 1> bufferLength) {
            bufferLength += checkedLength + 1;
            result = realloc(result, bufferLength * sizeof(_TCHAR));
        }
        
        if(resultLength > 0) {
            result[resultLength++] = pathSeparator;
            result[resultLength] = _T_ECLIPSE('\0');
        }
        _tcscpy(result + resultLength, checked);
        resultLength += checkedLength;
        
        if(checked != c1)
            free(checked);
        if(c2 != NULL)
            *(c2++) = pathSeparator;
        c1 = c2;
    }
    
    return result;
}

_TCHAR * concatStrings(_TCHAR**strs) {
    return concatPaths(strs, 0);
}

_TCHAR * concatPaths(_TCHAR** strs, _TCHAR separator) {
    _TCHAR separatorString[] = { separator, 0 };
    _TCHAR * result;
    int i = -1;
    size_t length = 0;
    /* first count how large a buffer we need */
    while (strs[++i] != NULL) {
        length += _tcslen(strs[i]) + (separator != 0 ? 1 : 0);
    }

    result = malloc((length + 1) * sizeof(_TCHAR));
    result[0] = 0;
    i = -1;
    while (strs[++i] != NULL) {
        result = _tcscat(result, strs[i]);
        if (separator != 0)
            result = _tcscat(result, separatorString);
    }
    return result;
}

/*
 * buffer contains a pathSeparator separated list of paths, check 
 * that it contains all the paths given.  Each path is expected to be
 * terminated with a pathSeparator character.
 */
int containsPaths(_TCHAR * str, _TCHAR** paths) {
    _TCHAR * buffer;
    _TCHAR * c;
    int i;
    
    /* terminate the string with a pathSeparator */
    buffer = malloc((_tcslen(str) + 2) * sizeof(_TCHAR));
    _stprintf(buffer, _T_ECLIPSE("%s%c"), str, pathSeparator);
    
    for (i = 0; paths[i] != NULL; i++) {
        c = _tcsstr(buffer, paths[i]);
        if ( c == NULL || !(c == buffer || *(c - 1) == pathSeparator))
        {
            /* entry not found */
            free(buffer);
            return 0;
        }
    }
    free(buffer);
    return 1;
}

int isVMLibrary( _TCHAR* vm )
{
    _TCHAR *ch = NULL;
    if (vm == NULL) return 0;
    ch = _tcsrchr( vm, '.' );
    if(ch == NULL)
        return 0;
#ifdef _WIN32
    return (_tcsicmp(ch, _T_ECLIPSE(".dll")) == 0);
#else
    return (_tcsicmp(ch, _T_ECLIPSE(".so")) == 0) || (_tcsicmp(ch, _T_ECLIPSE(".jnilib")) == 0) || (_tcsicmp(ch, _T_ECLIPSE(".dylib")) == 0);
#endif
}

#ifdef AIX

#include <sys/types.h>
#include <time.h>

/* Return the JVM version in the format x.x.x 
 */
char* getVMVersion( char *vmPath )
{
    char   cmd[MAX_LINE_LENGTH];
    char   lineString[MAX_LINE_LENGTH];
    char*  firstChar;
    char   fileName[MAX_LINE_LENGTH];
    time_t curTime;
    FILE*  fp;
    int    numChars = 0;
    char*  version  = NULL;

    /* Define a unique filename for the java output. */
    (void) time(&curTime);
    (void) sprintf(fileName, "/tmp/tmp%ld.txt", curTime);

    /* Write java -version output to a temp file */
    (void) sprintf(cmd,"%s -version 2> %s", vmPath, fileName);
    (void) system(cmd); 

    fp = fopen(fileName, "r");
    if (fp != NULL)
    {
        /* Read java -version output from a temp file */
        if (fgets(lineString, MAX_LINE_LENGTH, fp) == NULL)
            lineString[0] = '\0';
        fclose(fp);
        unlink(fileName);

        /* Extract version number */
        firstChar = (char *) (strchr(lineString, '"') + 1);
        if (firstChar != NULL)
            numChars = (int)  (strrchr(lineString, '"') - firstChar);
        
        /* Allocate a buffer and copy the version string into it. */
        if (numChars > 0)
        {
            version = malloc( numChars + 1 );
            strncpy(version, firstChar, numChars);
            version[numChars] = '\0';
        }
    }  

    return version;
}

/* Compare JVM Versions of the form "x.x.x..."
 *     
 *    Returns -1 if ver1 < ver2
 *    Returns  0 if ver1 = ver2 
 *    Returns  1 if ver1 > ver2
 */     
int versionCmp(char *ver1, char *ver2)
{
    char*  dot1;
    char*  dot2;
    int    num1;
    int    num2;

    dot1 = strchr(ver1, '.');
    dot2 = strchr(ver2, '.');

    num1 = atoi(ver1);
    num2 = atoi(ver2);

    if (num1 > num2)
        return 1;
        
    if (num1 < num2)
        return -1;
    
    if (dot1 && !dot2)   /* x.y > x */
        return 1;

    if (!dot1 && dot2)   /* x < x.y */
        return -1;
    
    if (!dot1 && !dot2)  /* x == x */
        return 0;

    return versionCmp((char*)(dot1 + 1), (char*)(dot2 + 1) );
}
#endif /* AIX */

課程總結

  • C 語言須要須要勤思考勤動手才能獲得提升
  • 難點部分爲指針的學習eclipse

    • 指針的本質,指針的運算,指針和數組
  • 學習過程能夠採用各個擊破的方法ide

    • 在一個特定的時間段只重點學習和練習某個主題
  • 在熟練掌握 C 語言的各個特性後再進行項目練習

部分書籍推薦:《C 專家編程》《C 陷阱與缺陷》《C 和指針》《編寫可讀性代碼的藝術》函數

以上內容參考狄泰軟件學院系列課程,請你們保護原創!學習

相關文章
相關標籤/搜索