c語言返回連結串列(malloc分配的字串)
阿新 • • 發佈:2019-01-26
一、函式返回頭指標(指向字串的指標)
以下程式碼返回了連結串列的頭指標,這種比較簡單
#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()掉,否則會造成記憶體洩漏。