问题操作C

时间:2017-10-15 04:54:32

标签: c arrays string segmentation-fault abort

我的方法是读取文件中的每个字符并保持计数,这样当我们点击非法字符时,我会跟踪字符串长度以及遇到此长度的字符串数量。现在我正在尝试使用我读入的字符构建字符串并将它们存储在数组中。它几乎正常工作,但是当我尝试将2个字符串放在一起时,我可以绕过中止和seg故障,在这两个字符串读入的情况下是相同的长度。如果你不介意给我一些反馈,我在我的代码第129行标记了我遇到的问题....我希望在我完成后打印每个长度的字符串

这是我用来测试的文本文件:

Tomorrow, and tomorrow, and tomorrow,
To the last syllable of recorded time;

源代码:

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

/*
 *this program reads in a text file from the command line
 *then counts and stores the number of words of all lengths
 */
#define LENGTH 34
#define WORD_BUFFER 750

int strLengths[LENGTH],lengthsCopy[LENGTH];
char *array[WORD_BUFFER][LENGTH];
char strings[LENGTH];
int counter = 0;
int ch,tester;

 //sorts the output of string lengths printing the largest amounts first
 void sort()
 {
    int max_val =0;
    int i,j,temp,val;
    //create copy
    for (i=0; i < LENGTH; i++)
    {
        lengthsCopy[i] = strLengths[i];
    }
    //for loop finds the max value in the array elements
    for(i=0; i<LENGTH; i++)
    {
        if(lengthsCopy[i] > max_val)
        max_val = lengthsCopy[i];
    }

    printf("max val in the array is %d\n",max_val);

    //prints the max value,decrements,checks,prints, rinse repeat...
    //iterates until the max is 0
    while(max_val!=0)
    {
        //checks all elements
        for(i=LENGTH-1; i > 0; i--)
        {
            //print when max val is found
            if(lengthsCopy[i] == max_val)
            {
                temp = i;
                printf("Count[%02d]=%02d;\n",i,max_val);
                //check for doubles
                for(j=LENGTH-1; j > 0; j--)
                {
                    //if double is found that is not the original, print
                    if(lengthsCopy[j] == max_val && temp != j)
                    {
                        printf("Count[%02d]=%02d;\n",j,max_val);
                        //erase value
                    lengthsCopy[j] = 0;
                    }
                }
            }
        }
        max_val--;
    }
}

//print all array that are not null, represent count of word lenghts
void printList()
{
    int i,val;
    for(i=1; i<=LENGTH;i++)
    {
        if(strLengths[i] > 0)
        {
        val = strLengths[i];
        printf("Count[%02d]=%02d;\n",i,val);
        }
    }
}

int main (int argc, char *argv[])
{
    //error message if input file is not passed
    if(argc < 2)
    {
        printf("You have to give me a file!\n");
        exit(1);
    }
    FILE *text = fopen(argv[1], "r");
    //errror message if no contents in the file
    if(text == NULL)
    {
        printf("No content to read in %s. \n", argv[1]);
        exit(1);
    }
    //iterate through text until end of file
    ch = fgetc(text);
    int strPoint =0;
    while(ch != EOF)
    {
        //if illegal char is met, add a count to the array value of current counter
        //set counter back to 0
        //scan next char
        if(ch==' '||ch==','||ch=='('||ch==')'||ch==';'||ch=='\n')
        {

            if(array[counter][0] == NULL)//if length not defined yet
            {
                array[counter][0] = strings;//add current string build to the array
                printf("%s\n",array[counter][0] );
            }
            else if(array[counter][0] != NULL && strings[0] != '\0')
            {//else length is defined add to text bank
                printf("else if reached\n");
                printf("%s\n",strings );
                printf("%lu\n",strlen(array[counter][0]) );
                int arrayptr = strlen(*array[counter]);
                printf("ptr %d",arrayptr);
                /* next line aborts / seg_faults */
                strncat(*array[counter],strings,strlen(strings)); 
            }

            strLengths[counter]++;
            counter = 0;
            ch = fgetc(text);
            memset(strings, 0, sizeof(strings));//clear stringBuild
            strPoint =0;
        }
        //else a legal character, increase counter, scan next char
        else
        {
            strings[strPoint] = ch;
            printf("string build %c\n",strings[strPoint]);
            counter++;
            strPoint++;
            ch = fgetc(text);
        }
    }
    fclose(text);
    printf("stored string %s\n",array[3][0] );

    printList();
    //call sort
    sort();

    exit(0);
}

1 个答案:

答案 0 :(得分:0)

从我的代码中可以看出,您的主要问题是您对所发生的事情的误解:

array[counter][0] = strings;//add current string build to the array

您正在将指针array[counter][0]设置为strings的地址。您只有一个 strings变量,因此每个array[counter][0]指向相同的内容(因此array中的每一行都将指向strings中包含的最后一个字符串{1}})

strncat作为strcpy nul-termianting 凭借strncat的行为,并没有错,但要注意它可以是长缓冲区的性能损失。您可能有其他逻辑问题,但它们被代码的笨拙布局混淆,而非标准地使用指向char 数组的数组。

<强>反馈

尝试并简化您的实施。如果您主要关心的是存储从文件中读取的单词以及每个单词的长度以进行排序,那么您可以将单词存储在二维char数组中,并在每次需要时调用strlen长度,或者int的大小,您可以使用简单的结构将每个单词的长度与单词本身相关联,例如

typedef struct {
    char word[LENGTH];
    int len;
} wordinfo;

然后,您只需创建一个数组或结构(例如wordinfo words[WORD_BUFFER];),并将您的单词存储在words[x].word中,并将长度存储在word[x].len中。如果你想放弃使用结构,那么只需声明一个二维数组(例如char words[LENGTH][WORD_BUFFER];并将单词存储在那里。(对于每字4字节的成本,如果存储不是问题,你可以通过存储读取字符时已有的长度来节省重复函数调用strlen的开销。)

您还可以声明指向char LENGTH 数组的指针(例如char (*array)[LENGTH];,并使用WORD_BUFFERarray = malloc (sizeof *array * WORD_BUFFER); calloc动态分配存储空间(您可以使用main()代替初始化分配给零的所有字节。这是一个不错的选择,但它似乎没有动态分配是你的目标。

此外,避免使用全局变量。它们几乎不需要,并且会增加名称冲突和值覆盖的风险。将变量声明为/* simple insertion sort on len (descending) */ void sort (wordinfo *a, int n) { int i, j; wordinfo v; for (i = 1; i < n; i++) { v = a[i]; j = i; while (j > 0 && a[j - 1].len < v.len ) { a[j] = a[j - 1]; j -= 1; } a[j] = v; } } /* tabular print of words read */ void printlist (wordinfo *a, int n) { int i; for (i = 0; i < n; i++) printf (" %-34s (%d-chars)\n", a[i].word, a[i].len); } 的本地变量,并根据需要将它们作为参数传递。例如,使用结构实现,您可以按长度编写排序并按如下方式打印,获取指向struct数组的指针和作为参数填充的数字:

qsort

注意:除非家庭作业需要,否则不要写或使用你自己的排序.C提供的qsort效率更高,经过充分测试,只需写一个比较函数来比较需要排序的两个元素,让LENGTH完成工作)

最后,从文件中读取每个字符的逻辑根本不需要复杂。只需读取字符,检查它,并采取适当的任何操作。唯一增加的复杂性来自测试,以确保您保持在WORD_BUFFER字符和 int c, len = 0, maxndx = 0, ndx = 0; wordinfo words[WORD_BUFFER] = {{ .word = "", .len = 0 }}; 字以防止覆盖存储的范围。甚至使用struct实现,声明并初始化为:

main

您可以简化 while (ndx < WORD_BUFFER && (c = fgetc (fp)) != EOF) { if (len + 1 == LENGTH || /* check if full or c matches */ c==' ' || c==',' || c=='(' || c==')' || c==';' || c=='\n') { if (len) { /* if we started a word */ if (len > words[maxndx].len) /* check if longest */ maxndx = ndx; /* update max index */ words[ndx].len = len; /* set words[x].len */ words[ndx++].word[len] = 0; /* nul-terminat word */ len = 0; /* reset length */ } } else words[ndx].word[len++] = c; /* assign c to words[x].word[len] */ } 中的读取逻辑,只需:

maxndx

注意: ndx只保存包含最长单词的结构的索引(#include <stdio.h> #define LENGTH 34 #define WORD_BUFFER 750 typedef struct { char word[LENGTH]; int len; } wordinfo; /* simple insertion sort on len (descending) */ void sort (wordinfo *a, int n) { int i, j; wordinfo v; for (i = 1; i < n; i++) { v = a[i]; j = i; while (j > 0 && a[j - 1].len < v.len ) { a[j] = a[j - 1]; j -= 1; } a[j] = v; } } /* tabular print of words read */ void printlist (wordinfo *a, int n) { int i; for (i = 0; i < n; i++) printf (" %-34s (%d-chars)\n", a[i].word, a[i].len); } int main (int argc, char **argv) { int c, len = 0, maxndx = 0, ndx = 0; wordinfo words[WORD_BUFFER] = {{ .word = "", .len = 0 }}; FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin; if (!fp) { /* validate file open for reading */ fprintf (stderr, "error: file open failed '%s'.\n", argv[1]); return 1; } /* read each char and store in words[x].word up to 'ndx' words. * save the length of each word in words[x].len. */ while (ndx < WORD_BUFFER && (c = fgetc (fp)) != EOF) { if (len + 1 == LENGTH || /* check if full or c matches */ c==' ' || c==',' || c=='(' || c==')' || c==';' || c=='\n') { if (len) { /* if we started a word */ if (len > words[maxndx].len) /* check if longest */ maxndx = ndx; /* update max index */ words[ndx].len = len; /* set words[x].len */ words[ndx++].word[len] = 0; /* nul-terminat word */ len = 0; /* reset length */ } } else words[ndx].word[len++] = c; /* assign c to words[x].word[len] */ } if (fp != stdin) fclose (fp); /* close file if not stdin */ printf ("\nlongest word: '%s' (%d-chars)\n\n", words[maxndx].word, words[maxndx].len); printf ("words read from file:\n\n"); printlist (words, ndx); /* print words in order read */ sort (words, ndx); printf ("\nwords sorted by length:\n\n"); printlist (words, ndx); /* print words sorted by length */ return 0; } ),或者最长的一个是您拥有多个单词的结构相同的最大长度)

完全可以这样做,你可以将代码简化为:

stdin

注意:程序要求将文件名作为第一个参数读取,否则如果没有给出参数,它将从$ ./bin/rdstrings3 <dat/tomorrow.txt longest word: 'Tomorrow' (8-chars) words read from file: Tomorrow (8-chars) and (3-chars) tomorrow (8-chars) and (3-chars) tomorrow (8-chars) To (2-chars) the (3-chars) last (4-chars) syllable (8-chars) of (2-chars) recorded (8-chars) time (4-chars) words sorted by length: Tomorrow (8-chars) tomorrow (8-chars) tomorrow (8-chars) syllable (8-chars) recorded (8-chars) last (4-chars) time (4-chars) and (3-chars) and (3-chars) the (3-chars) To (2-chars) of (2-chars) 读取(默认情况下)

示例使用/输出

len

仔细看看,如果您有任何疑问,请告诉我。选择使用结构并存储strlen或仅在需要的地方调用{{1}}完全取决于您。