使用c语言处理字符串(split字符串和删除多余的空格)

目录

一、我之前的程序

1.删除空格和分割字符串的函数(第一版)

2.split修改的版本一(也是错的。。。可以不看),

二、split 修改的版本二,成功的版本

 1.指针数组版本

 2.动态内存分配版本

三、总结

四、致谢


一、我之前的程序

下面的程序主要用来处理字符串,注意那个分割字符串的函数错了,有问题,但是在这里我没有删掉它,因为在后面我要依靠他来分析我的问题。我在写博客的时候没有测试这些函数,凭感觉写的,所以可能都会有问题,哈哈,不骂我。

1.删除空格和分割字符串的函数(第一版)

/**
 * @copyright   Copyright (c) 2023 Jiawshi
 * @author      Jiawshi (jiawshi@126.com)
 * 
 * @file        dlstring.h
 * @brief       处理字符串
 * 
 * @version     V0.01
 * @date        2023-04-13
 * 
 * @note        历史记录: 
 *              - [2023-04-13] [Jiawshi] 创建初始版本
 * @warning     
 * @par         修改记录: 
 * <table>
 * <tr><th>date          <th>Version    <th>Author      <th>Description    </tr>
 * <tr><td>2023-04-13    <td>V0.01      <td>Jiawshi       <td>创建初始版本    </tr>
 * </table>
 */
#ifndef DLSTRING_H
#define DLSTRING_H


/**
 * @fn        del_leftspace
 * @brief     处理字符串,删除左边的空格和水平制表符
 * 
 * @param     [in] str              字符串
 * 
 * @return    int                   success or fail
 */
int del_leftspace(char *str);

/**
 * @fn        int del_rightspace(char *str)
 * @brief     删除字符串右边的空格和水平制表符
 * 
 * @param     [in] str       字符串
 * 
 * @return    int            success or fail
 */
int del_rightspace(char *str);

/**
 * @fn        int del_strspace(char *str)
 * @brief     删除字符串左边和右边的空格和水平制表符
 * 
 * @param     [in] str       字符串
 * 
 * @return    int            success or fail
 */
int del_strspace(char *str);

// /**
//  * @fn          char *split_str(char *str)
//  * @brief       按照空格或者制表符把字符串分割
//  *              
//  * @param       [in] str            待分割的字符串
//  * @param       [in] delim          按照delim分割
//  * 
//  * @return      char**              指向字符串数组的首地址
//  */
// char **split_str(char *str, char *delim);

/**
 * @fn          char *split_str(char *str)
 * @brief       按照delim把字符串分割
 * 
 * @param       [in] str            待分割的字符串
 * @param       [in] delim          按照delim分割
 * @param       [in] newstr         分割后的结果
 * @param       [in] num            分割后数组大小
 * 
 * @return                       
 */
void split_str(char *str, char *delim, char **newstr, int *num);

#endif
#include "dlstring.h"
#include "errorcode.h"
#include <stdio.h>
#include "command.h"
#include <string.h>


int del_leftspace(char *str)
{
    if(str == NULL){
        return PTRNULL;
    }
    int len = 0;
    int i = 0;
    int j = 0;
    len = strlen(str);
    while(str[i] == 0x20 || str[i] == 0x09){
        i++;
        if(len == i){
            break;
        }
    }

    if(i== 0){
        return 0;
    }

    while(str[i] != '\0'){
        str[j++] = str[i++];
    }
    str[j] = '\0';
    return 0;
}

int del_rightspace(char *str)
{
    if(str == NULL){
        return PTRNULL;
    }

    int len = 0;
    int i = 0;
    int j = 0;

    len = strlen(str);
    i = len -1;
    while(str[i] == 0x20 || str[i] == 0x09){
        i--;
        if(i == -1){
            str = NULL;
            return 0;
        }
    }
    
    if(i == len -1){
        return 0;
    }
    
    str[i] = '\0';
    return 0;
}

int del_strspace(char *str)
{
    if(del_leftspace(str) < 0){
        return PTRNULL;
    }

    if(del_rightspace(str) < 0){
        return PTRNULL;
    }
    return 0;
}

// char **split_str(char *str, char *delim)
// {
//     char *s = NULL;
//     char *pp[10] = {0};
//     char **p = NULL;
//     int count = 0;
//     int total = 0;

//     while((s = strsep(&str, delim)) != NULL){
//         if(strcmp(s, "") == 0){
//             continue;
//         }
//         pp[count] = s;
//         total += strlen(s);
//         count++;
//     }

//     if(total == 0){
//         return NULL;
//     }

//     *p = realloc(pp, total);
//     return p;
// }

void split_str(char *str, char *delim, char **newstr, int *num)
{
    char *s = NULL;
    char *pp[10] = {0};
    int count = 0;
    int total = 0;

    while((s = strsep(&str, delim)) != NULL){
        if(strcmp(s, "") == 0){
            continue;
        }
        pp[count] = s;
        total += strlen(s);
        count++;
    }

    if(total == 0){
        newstr = NULL;
    }

    *newstr = realloc(pp, total);
    *num = count;
    
}

2.split修改的版本一(也是错的。。。可以不看),

我在修改程序的时候,测试了好多版本所以我的文章可能会看起来有点长。

我在使用我前面的版本的时候发现原来我的程序是错的。是我对二级指针和指针数组的理解有问题,所以我进行了如下修改,(printf函数有点多,有点乱)

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

void split_str(char *str, char *delim, char **newstr, int *num)
{
    char *s = NULL;
    char *pp;
    int count = 0;
    int total = 0;

    while((s = strsep(&str, delim)) != NULL){
        if(strcmp(s, "") == 0){
            continue;
        }
        pp = malloc(strlen(s)+ 1);
        pp = strdup(s);
        newstr[count] = realloc(pp, strlen(pp));

        total += strlen(s) + 1;
        count++;
    }

   

    if(total == 0){
        newstr = NULL;
    }
    int i;

    for(i = 0; i < count; i++){
        printf("%d str: %s\n", i, newstr[i]);
    }

    newstr[count] = NULL;
    *num = count;
    
}

int main(int argc, char **argv)
{
    char **newstr;
    char str[256];
    
    while(fgets(str, 256, stdin) == NULL){
        ;
    }
    int num;
    split_str(str, " ", newstr, &num);
    int i;
    char **t = newstr;
    for(i = 0; i < num; i++){
        if(t[i] != NULL)
            printf("%d %s\n", i, t[i]);
    }

}

 这个程序在我的ubuntu上是错的,但是呢在我的deepin上是对的。于是乎,我看看了我的程序。嗯,他是错的。。。

deepin上的结果是

 后来又有个版本,在deepin上测试

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

void split_str(char *str, char *delim, char **newstr, int *num)
{
    char *s = NULL;
    char *pp;
    int count = 0;
    int total = 0;

    while((s = strsep(&str, delim)) != NULL){
        if(strcmp(s, "") == 0){
            continue;
        }
        pp = malloc(strlen(s)+ 1);
        pp = strdup(s);

        *newstr = (char *)realloc(pp, strlen(pp));
  
        total += strlen(s) + 1;
        count++;
    }

   

    if(total == 0){
        newstr = NULL;
    }
    int i;
    
    for(i = 0; i < count; i++){
        printf("%d str: %s\n", i, newstr[i]);
    }

    *num = count;
    
}

int main(int argc, char **argv)
{
    char **newstr;
    char str[256];

    while(fgets(str, 256, stdin) == NULL){
        ;
    }
    int num;
    split_str(str, " ", newstr, &num);
    int i;
    char **t = newstr;
   
    for(i = 0; i < num; i++){
        printf(" %d %s\n", i, t[i]);
    }

}

问题是他跟上面的好像没啥区别,但是结果却区别大了

发生了什么?我也不知道。。。

二、split 修改的版本二,成功的版本

 1.指针数组版本

我清楚的明白我的二级指针用错了,但是呢,我并不想将char  **newstr  换成char *newstr[10]. 在多次修改没有成功后,我的同学帮我修改了程序。 他用的是char *newstr[10],   但是预先的判断我有多少字串是我不愿意做的。后来他又给了我其他的版本在后面。

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

#define PRT(fmt, ...) fprintf(stdout, "[%s:%04d @ <%s>]" fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)

void split_str(char *str, char *delim, char **newstr, int *num)
{
    if (NULL == str || NULL == delim || NULL == newstr || NULL == num)
    {
        PRT("val is NULL\n");
        return;
    }
    char *s = NULL;
    char *pp = NULL;
    int count = 0;
    int total = 0;

    while ((s = strsep(&str, delim)) != NULL)
    {
    if (strcmp(s, "") == 0)
    {
        continue;
    }
    pp = (char *)malloc(strlen(s) + 1);
    PRT("sizeof pp %lu\n", strlen(s) + 1);
    if (NULL == pp)
    {
    PRT("malloc pp err\n");
    return;
    }
    pp = strdup(s);
    PRT("%lu\n", strlen(pp));
    newstr[count] = (char *)realloc(pp, strlen(pp));
    if (NULL == newstr[count])
    {
        PRT("realloc error\n");
        free(pp);
        return;
    }
    PRT("====\n");
    PRT("str: %s\n", newstr[count]);
    total += strlen(s) + 1;
    count++;
    }

    PRT("===\n");

    if (total == 0)
    {
        newstr = NULL;
        goto EXITNUL;
    }

    for (int i = 0; i < count; i++)
    {
    PRT("%d str: %s\n", i, newstr[i]);
    }

EXITNUL:
    *num = count;

    return;
}

int main(int argc, char **argv)
{
    char *newstr[10] = {NULL};
    char str[256];
    char **t = NULL;
    int num;
    while (fgets(str, 256, stdin) == NULL)
    {
    }

    split_str(str, " ", newstr, &num);
    t = newstr;
    PRT("fjlds\n");
    for (int i = 0; i < num; i++)
    {
    PRT(" %d %s\n", i, t[i]);
    }

    while (num > 0)
    {
    free(newstr[num - 1]);
    newstr[num - 1] = NULL;
    num--;
    }

    return 0;
}

当他给我发程序的时候,我特别感慨,工作的人与我这在学校的人写的程序还真是特别不一样,我的程序就跟屎一样,他帮我修改了后看起来感觉都不一样。

首先呢我觉得他的PRT函数写的不错,然后呢我觉得free的习惯很好,非常好。

 2.动态内存分配版本

下面是他写的动态内存分配的版本,也就是我使用 char **newstr,来完成任务的版本,之所以我没有成功,是因为我在newstr[i]  = realloc(pp, sizeof(pp)),之前没有给newstr来分配空间,之前我一直以为我每次realloc是分配了空间的, 那么我每次只要使用newstr[i],就可以知道字符串的内容。显然我错了。

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

#define PRT(fmt, ...) fprintf(stdout, "[%s:%04d @ <%s>]" fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)

/* 注意此处:为什么返回char **,因为 char **newstr 实际上是副本,再函数里修改后,函数返回后副本消失,但是手动分配的空间并不会消失,只能将原来分配空间的指针返回出去 */
char **split_str(char *str, char *delim, char **newstr, int *num)
{
    /* 此处注释了 NULL == newstr */
    if (NULL == str || NULL == delim /* || NULL == newstr */ || NULL == num)
    {
        PRT("val is NULL\n");
        return NULL;
    }
    /* 注意此处 后续直接使用str会使str指针发生变化 */
    /* strsep函数会修改源字符串,所以此处拷贝一个副本,用于计算一共有几个子串 */
    /* 可以用其他方法进行替代,效果可能更好 */

    /*         计算一共几个子串        */
    char *strPos = (char *)malloc(256);
    if (NULL == strPos)
    {
        goto EXITNUL;
    }
    memcpy(strPos, str, 256);
    char *s = NULL;
    char *pp = NULL;
    int count = 0;
    int total = 0;

    while ((s = strsep((char **)&strPos, delim)) != NULL)
    {
        if (strcmp(s, "") == 0)
        {
            continue;
        }
        count++;
    }
    /*         计算一共几个子串        */

    /* 给char ** newstr 分配内存,相当于指针数组 */
    if (count > 0)
    {
        PRT("count %d\n", count);
        newstr = (char **)malloc(count * sizeof(char *));
        if (NULL == newstr)
        {
            PRT("malloc newstr err\n");
            goto EXITNUL;
        }
        PRT("sizeof newstr = %lu\n", sizeof(newstr));
    }
    else
    {
        goto EXITNUL;
    }
    /* count 重新置零,规范一点应该定义个新的变量 */
    count = 0;

    while ((s = strsep(&str, delim)) != NULL)
    {
        if (strcmp(s, "") == 0)
        {
            continue;
        }
        pp = (char *)malloc(strlen(s) + 1);
        PRT("sizeof pp %lu\n", strlen(s) + 1);
        if (NULL == pp)
        {
            PRT("malloc pp err\n");
            return NULL;
        }
        pp = strdup(s);
        PRT("%lu\n", strlen(pp));
        /***/
        // newstr[count] = (char *)realloc(pp, strlen(pp));
        /* 注意此处:给指针数组的每一个指针分配空间 */
        newstr[count] = (char *)malloc(strlen(pp));
        if (NULL == newstr[count])
        {
            PRT("realloc error\n");
            free(pp);
            pp = NULL;
            break;
        }
        memcpy(newstr[count], pp, strlen(pp));
        free(pp);
        pp = NULL;

        PRT("====\n");
        PRT("str: %s\n", newstr[count]);
        total += strlen(s) + 1;
        count++;
    }

    PRT("===\n");

    if (total == 0)
    {
        newstr = NULL;
        goto EXITNUL;
    }

    for (int i = 0; i < count; i++)
    {
        if (NULL == newstr[i])
        {
            PRT("newstr[i] is NULL\n");
        }
        PRT("%d str: %s\n", i, newstr[i]);
    }

EXITNUL:
    *num = count;

    return newstr;
}

int main(int argc, char **argv)
{
    char **newstr;
    char **t = NULL;
    char str[256];
    int num;
    while (fgets(str, 256, stdin) == NULL)
    {
    }
    t = split_str(str, " ", newstr, &num);
    PRT("fjlds\n");
    if (NULL == t)
    {
        PRT("NULL\n");
        return 0;
    }

    for (int i = 0; i < num; i++)
    {
        PRT(" %d %s\n", i, t[i]);
    }
    /***********************************************/
    /*                   内存释放                   */
    /***********************************************/
    while (num > 0)
    {
        if (NULL != t[num - 1])
        {
            free(t[num - 1]);
            t[num - 1] = NULL;
        }
        num--;
    }
    free(t);
    t = NULL;
    /***********************************************/
    PRT("return\n");
    return 0;
}

下面是最终的函数

char **split_str(char *str, char *delim, char **newstr, int *num)
{
    if (NULL == str || NULL == delim || NULL == num)
        return NULL;
    int len = strlen(str);
    char *strpos = (char *)malloc(len + 1);
    if (NULL == strpos)
        goto EXITNULL;
    
    memcpy(strpos, str, len);
    strpos[len] = '\0';
    char *s = NULL;
    char *p = NULL;
    int count = 0;
    int total = 0;

    while ((s = strsep((char **)&strpos, delim)) != NULL) {
        if (strcmp(s, "") == 0)
            continue;
        count++;
    }

    if (count > 0) {
        newstr = (char **)malloc(count * sizeof(char *));
        if (NULL == newstr)
            goto EXITNULL;
    } else
        goto EXITNULL;
    *num = count;
    count = 0;

    while ((s = strsep((char **)&str, delim)) != NULL) {
        if (strcmp(s, "") == 0)
            continue;
        p = (char *)malloc(strlen(s) + 1);
        if (NULL == p)
            return NULL;
        p = strdup(s);
        newstr[count] = (char *)malloc(strlen(p));
        if (NULL == newstr[count]) {
            free(p);
            p = NULL;
            break;
        }
        memcpy(newstr[count], p, strlen(p));
        free(p);
        total += strlen(s) + 1;
        count++;
    }

    if (total == 0) {
        newstr = NULL;
        goto EXITNULL;
    }

    return newstr;

他这个程序呢,主要是先获了需要分割的字串的个数。然后再去为newstr申请空间,也就是得到指针数组的大小,比如字串为10个,那么就是char *newstr[10]。然后再给每个newstr[i]指针赋值。

三、总结

        通过我的错误的版本和正确的版本,我对于char **p 和char *p[]的使用有了更深的理解,同时对动态内存分配的理解也更深了。

四、致谢

非常感谢我的同学给我的帮助。 

看了他的程序,我受益匪浅,首先他的良好的编程习惯,我自愧不如,其次我也通过他的程序学到了很多的编程技巧。再次感谢他在工作时还抽出时间帮我解决问题。我这个呆在学校的还要再努力。

 欢迎批评指正!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言本身并没有提供字符串split的函数,但可以通过自定义函数实现这个功能。一般来说,实现字符串split需要考虑几个关键点: 1. 分隔符:需要指定字符串的分隔符,一般可以使用空格、逗号、分号等符号作为分隔符。 2. 字符串数组:需要定义一个字符数组来存储分割后的子字符串。 3. 计数器:需要定义一个计数器来记录分割后得到的字符串数量。 4. 循环:需要在循环中逐个读取字符,并根据分隔符将字符分割为子字符串。 以下是一个简单的字符串split函数示例: ```c void split(char* str, char delim, char** result, int* count) { char* p = str; char* start = p; while (*p) { if (*p == delim) { *p = '\0'; result[(*count)++] = start; start = p + 1; } p++; } result[(*count)++] = start; } ``` 这个函数接受三个参数:要分割的字符串,分隔符以及存储结果的字符串数组和计数器。在函数内部,先定义了两个指针p和start,分别指向字符串的起始位置和分隔符的位置。然后,在循环里每次读取一个字符,遇到分隔符就将其替换为字符串结束符\0,同时将start指向下一个子字符串的起始位置。最后,将最后一个子字符串添加到结果数组中,并返回结果。 需要注意的是,这个函数假设调用者已经在外部分配了结果数组和计数器,因此在使用前需要先为这两个变量分配空间。另外,由于C语言本身并没有提供字符串类型,因此使用字符串操作时需要特别注意字符串结束符的处理以及字符串的长度问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值