1. 程式人生 > >c語言返回連結串列(malloc分配的字串)

c語言返回連結串列(malloc分配的字串)

一、函式返回頭指標(指向字串的指標)
以下程式碼返回了連結串列的頭指標,這種比較簡單

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

//對於缺測"////"則記錄特徵值999.999
sta_data *readregfile(char *path,char *filename,FILE *log_fp)
{
    sta_data *pHead,*p,*pTail;

    pHead=pTail=(sta_data*)malloc
(LEN_DATA); char fileallname[512]; sprintf(fileallname,"%s/%s",path,filename); FILE* reg_fp = fopen(fileallname, "r"); char line[300]; int num=0;//記錄當前讀取的num行,前提是每組有四行 int line_num=0;//記錄真實的行數 int group=0;//記錄站數,也就是第幾組 struct station_temp sta_temp; while (fgets(line, sizeof
(line), reg_fp)) { line_num++; if(num-group*4==0)//解析第一行(基本資訊) { if(reglen(line)==34) { int f_status=sscanf(line,"%5s",sta_temp.station_num); strncpy(sta_temp.first,line,34);sta_temp.first[34]='\0'
; if(f_status!=1) { //重新對錯誤資料進行異常值賦值,並提醒錯誤資料 sprintf(sta_temp.station_num,"99999"); fprintf(log_fp,"%s %d 基本資訊位元組數正確,格式錯誤\n",filename,line_num); } } else { sprintf(sta_temp.station_num,"99999"); strncpy(sta_temp.first,line,34);sta_temp.first[34]='\0'; fprintf(log_fp,"%s %d 基本資訊行的位元組數不正確\n",filename,line_num); } num++; continue; } else if(num-group*4==1)//解析第二行(主要要素) { if(reglen(line)==262) { int s_status=sscanf(line,"%14s %*s %3s %*s %3s %*s %3s %*s %*s %3s \ %*s %3s %*s %4s %4s %4s %*s %4s %*s %*s %*s %*s %*s %*s %5s %5s %*s %5s %*s %4s \ %4s %*s %4s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %5s %*s %*s %*s", \ sta_temp.o_time,sta_temp.wind2,sta_temp.wind10,sta_temp.wind_max,sta_temp.wind_s,sta_temp.wind_j, \ sta_temp.rain,sta_temp.tem,sta_temp.tem_max,sta_temp.tem_min,sta_temp.pres,sta_temp.pres_max,sta_temp.pres_min, \ sta_temp.g_temp,sta_temp.g_temp_max,sta_temp.g_temp_min,sta_temp.s_pres); strncpy(sta_temp.second,line,262);sta_temp.second[262]='\0'; if(s_status!=17) { //重新對錯誤資料進行異常值賦值,並提醒錯誤資料 sprintf(sta_temp.o_time,"99999999999999"); fprintf(log_fp,"%s %d 第二段觀測資料位元組數正確,格式錯誤\n",filename,line_num); } } else { //重新對錯誤資料進行異常值賦值,並提醒錯誤資料 sprintf(sta_temp.o_time,"99999999999999"); fprintf(log_fp,"%s %d 第二行觀測資料的位元組數不正確\n",filename,line_num); } num++; } else if(num-group*4==2)//解析第三行(小時內分鐘降水) { strncpy(sta_temp.three,line,121);sta_temp.three[121]='\0'; num++; } else if(num-group*4==3)//解析第四行 { group++; if(reglen(line)==34) { //讀到了新的臺站資料 //0、將第四行賦值為NNNN strncpy(sta_temp.four,"NNNN",135);sta_temp.four[135]='\0'; strncpy(sta_temp.filename,filename,63);sta_temp.filename[63]='\0'; //1、先將上一個格式正確的臺站資料寫入 if(strcmp(sta_temp.station_num,"99999")!=0 && strcmp(sta_temp.o_time,"99999999999999")!=0) { //格式正確的資料寫入 p=pTail; pTail=(sta_data*)malloc(LEN_DATA); strtodouble(pTail,&sta_temp);//將字串格式轉換為double格式 p->next=pTail; } //2、置空結構體 memset(&sta_temp,0,sizeof(struct station_temp)); //3、讀取新的臺站的第一行資料 int n_status=sscanf(line,"%5s",sta_temp.station_num); strncpy(sta_temp.first,line,34);sta_temp.first[34]='\0'; if(n_status!=1) { //重新對錯誤資料進行異常值賦值,並提醒錯誤資料 sprintf(sta_temp.station_num,"99999"); printf("format.err-[基本資訊位元組數正確,格式錯誤]-line:%d-file:%s\n",line_num,filename); } num=num+2; } else if(reglen(line)==135||line[0]=='N')//水文站末尾行為NNNN ,由於有空格,所以reglen(line)==5 { //讀取能見度或者NNNN資料 sprintf(sta_temp.four,line); sprintf(sta_temp.filename,filename); //將本次臺站的資料寫入 if(strcmp(sta_temp.station_num,"99999")!=0 && strcmp(sta_temp.o_time,"99999999999999")!=0) { //格式正確的資料寫入 p=pTail; pTail=(sta_data*)malloc(LEN_DATA); strtodouble(pTail,&sta_temp);//將字串格式轉換為double格式 p->next=pTail; } //2、置空結構體 memset(&sta_temp,0,sizeof(struct station_temp)); num++; } else { fprintf(log_fp,"%s %d 這個站的資料格式錯誤,以下資料不再讀取\n",filename,line_num); pTail->next=NULL; return(pHead); } } } fclose(reg_fp); pTail->next=NULL; return(pHead); }

以下程式碼返回字串指標

#include <stdio.h>
#include <malloc.h>
#include <string.h>

char* test()
{
    char *p;
    p = (char*)malloc(10 * sizeof(char));
    strcpy(p, "123456789" );
    return p;
}

void main()
{
    char *str = NULL ;
    str = test();
    printf("%s\n", str);
    free(str);
}

二、通過二級指標返回引數
以下程式碼通過將頭指標作為引數傳遞給函式,實現給連結串列賦值

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

//對於缺測"////"則記錄特徵值999.999
int readregfile(char *path,char *filename,FILE *log_fp,sta_data **pHead)
{
    sta_data *p,*pTail;

    *pHead=pTail=(sta_data*)malloc(LEN_DATA);

    char fileallname[512];
    sprintf(fileallname,"%s/%s",path,filename);
    FILE* reg_fp = fopen(fileallname, "r");
    char line[300];
    int num=0;//記錄當前讀取的num行,前提是每組有四行
    int line_num=0;//記錄真實的行數
    int group=0;//記錄站數,也就是第幾組

    struct station_temp sta_temp;

    while (fgets(line, sizeof(line), reg_fp))
      {
         line_num++;
         if(num-group*4==0)//解析第一行(基本資訊)
            {
               if(reglen(line)==34)
                 {
                    int f_status=sscanf(line,"%5s",sta_temp.station_num);
                    strncpy(sta_temp.first,line,34);sta_temp.first[34]='\0';
                    if(f_status!=1)
                       {
                         //重新對錯誤資料進行異常值賦值,並提醒錯誤資料
                         sprintf(sta_temp.station_num,"99999");
                         fprintf(log_fp,"%s %d 基本資訊位元組數正確,格式錯誤\n",filename,line_num);
                       }
                 }
               else
                  {
                     sprintf(sta_temp.station_num,"99999");
                     strncpy(sta_temp.first,line,34);sta_temp.first[34]='\0';
                     fprintf(log_fp,"%s %d 基本資訊行的位元組數不正確\n",filename,line_num);
                  }
               num++;
               continue;
            }
         else if(num-group*4==1)//解析第二行(主要要素)
            {
               if(reglen(line)==262)
                 {
                   int s_status=sscanf(line,"%14s %*s %3s %*s %3s %*s %3s %*s %*s %3s \
                   %*s %3s %*s %4s %4s %4s %*s %4s %*s %*s %*s %*s %*s %*s %5s %5s %*s %5s %*s %4s \
                   %4s %*s %4s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %5s %*s %*s %*s", \
                   sta_temp.o_time,sta_temp.wind2,sta_temp.wind10,sta_temp.wind_max,sta_temp.wind_s,sta_temp.wind_j, \
                   sta_temp.rain,sta_temp.tem,sta_temp.tem_max,sta_temp.tem_min,sta_temp.pres,sta_temp.pres_max,sta_temp.pres_min, \
                   sta_temp.g_temp,sta_temp.g_temp_max,sta_temp.g_temp_min,sta_temp.s_pres);
                   strncpy(sta_temp.second,line,262);sta_temp.second[262]='\0';
                   if(s_status!=17)
                       {
                         //重新對錯誤資料進行異常值賦值,並提醒錯誤資料
                         sprintf(sta_temp.o_time,"99999999999999");
                         fprintf(log_fp,"%s %d 第二段觀測資料位元組數正確,格式錯誤\n",filename,line_num);
                       }
                 }
               else
                  {
                     //重新對錯誤資料進行異常值賦值,並提醒錯誤資料
                     sprintf(sta_temp.o_time,"99999999999999");
                     fprintf(log_fp,"%s %d 第二行觀測資料的位元組數不正確\n",filename,line_num);
                  }
               num++;
           }
         else if(num-group*4==2)//解析第三行(小時內分鐘降水)
            {
               strncpy(sta_temp.three,line,121);sta_temp.three[121]='\0';
               num++;
           }
         else if(num-group*4==3)//解析第四行
            {
               group++;
               if(reglen(line)==34)
                 {
                    //讀到了新的臺站資料
                    //0、將第四行賦值為NNNN
                    strncpy(sta_temp.four,"NNNN",135);sta_temp.four[135]='\0';
                    strncpy(sta_temp.filename,filename,63);sta_temp.filename[63]='\0';
                    //1、先將上一個格式正確的臺站資料寫入
                    if(strcmp(sta_temp.station_num,"99999")!=0 && strcmp(sta_temp.o_time,"99999999999999")!=0)
                      {
                         //格式正確的資料寫入
                         p=pTail;
                         pTail=(sta_data*)malloc(LEN_DATA);
                         strtodouble(pTail,&sta_temp);//將字串格式轉換為double格式
                         p->next=pTail;
                      }
                    //2、置空結構體
                    memset(&sta_temp,0,sizeof(struct station_temp));
                    //3、讀取新的臺站的第一行資料
                    int n_status=sscanf(line,"%5s",sta_temp.station_num);
                    strncpy(sta_temp.first,line,34);sta_temp.first[34]='\0';
                    if(n_status!=1)
                       {
                         //重新對錯誤資料進行異常值賦值,並提醒錯誤資料
                         sprintf(sta_temp.station_num,"99999");
                         printf("format.err-[基本資訊位元組數正確,格式錯誤]-line:%d-file:%s\n",line_num,filename);
                       }
                    num=num+2;
                 }
               else if(reglen(line)==135||line[0]=='N')//水文站末尾行為NNNN ,由於有空格,所以reglen(line)==5
                 {
                    //讀取能見度或者NNNN資料
                    sprintf(sta_temp.four,line);
                    sprintf(sta_temp.filename,filename);
                    //將本次臺站的資料寫入
                    if(strcmp(sta_temp.station_num,"99999")!=0 && strcmp(sta_temp.o_time,"99999999999999")!=0)
                      {
                         //格式正確的資料寫入
                         p=pTail;
                         pTail=(sta_data*)malloc(LEN_DATA);
                         strtodouble(pTail,&sta_temp);//將字串格式轉換為double格式
                         p->next=pTail;
                      }
                    //2、置空結構體
                    memset(&sta_temp,0,sizeof(struct station_temp));
                    num++;
                 }
               else
                 {
                    fprintf(log_fp,"%s %d 這個站的資料格式錯誤,以下資料不再讀取\n",filename,line_num);
                    pTail->next=NULL;
                    return(group);
                 }
           }
      }
    fclose(reg_fp);
    pTail->next=NULL;
    return(group);
}

以下程式碼是字串賦值方式

#include <stdio.h>
#include <malloc.h>
#include <string.h>

void test(char **p)
{
    *p = (char*)malloc(10 * sizeof(char));
    strcpy(*p, "123456789" );   
}

void main()
{
    char *str = NULL ;
    test(&str);
    printf("%s\n", str);
    free(str);
}

三、常見誤區
1、使用一級指標

#include <stdio.h>
#include <malloc.h>
#include <string.h>

void test(char *p) 
{
    p = (char*)malloc(10 * sizeof(char));
    strcpy(*p, "123456789" );   
}

void main()
{
    char *str = NULL ;
    test(str);
    printf("%s\n", str);
    free(str);
}

看上去合情合理,把malloc得的地址賦給指標p,這樣我們傳入的str就指向申請的記憶體了。但事實是,str的值並沒有變化。先看下面程式碼

#include <stdio.h>

void test(char c)
{
    c = 'B';
}

void main()
{
    char ch = 'A' ;
    test(ch);
    printf("%c\n", ch);
}

呼叫test()後,主函式裡面的ch值還是’A’,而不是’B’。這是因為在呼叫函式的時候,char c 事實上是被複制進函式內部的,函式內的操作不會影響到原值。
  指標也是一樣的道理。傳入一個一級指標,只能修改它指向的資料,而不能修改它指向的地址。所以我們應該傳入一個二級指標,這個指標指向一級指標。這樣我們就能修改位於二級指標指向的資料,即一級指標指向的地址了。

2、二級指標未指向存在的一級指標

#include <stdio.h>
#include <malloc.h>
#include <string.h>

void test(char **p)
{
    *p = (char*)malloc(10 * sizeof(char));
    strcpy(*p, "123456789" );   
}

void main()
{
    char **str = NULL ; //原始碼:char *str = NULL;
    test(str);          //       test(&str);
    printf("%s\n", str);
    free(str);
}

為什麼我使用了二級指標,仍然是錯誤的呢?對比下正確的程式碼,就一目瞭然了。正確程式碼中,通過對一級指標str進行取址,得到指向str的二級指標,在子函式中就可以操作str的值了。而錯誤程式碼中,二級指標的值為NULL,這樣的花子函式中操作的是地址為NULL的記憶體,這當然是不對的。

四、使用free釋放記憶體
molloc申請的記憶體是位於堆中的,不用後要記得free()掉,否則會造成記憶體洩漏。