简体   繁体   中英

longest string array segmentation fault

Write a C function longestStrInAr() that takes in an array of strings str and size (>0) as parameters, and returns the longest string and also the length of the longest string via the pointer parameter length. If two or more strings have the same longest string length, then the first appeared string will be returned to the calling function. For example, if size is 5 and the array of strings is { "peter", "john", "mary", "jane", "kenny"} , then the longest string is "peter" and the string length is 5 will be returned to the calling function

I am getting a segmentation fault here and I don't know why.

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

#define N 20

char *longestStrInAr(char str[N][40], int size, int *length);

int main() {
    int i, size, length;   
    char str[N][40], first[40], last[40], *p, *result;
    char dummychar;   
    
    printf("Enter array size: \n");
    scanf("%d", &size);
    scanf("%c", &dummychar);
    for (i = 0; i < size; i++) {
        printf("Enter string %d: \n", i + 1);
        fgets(str[i], 40, stdin);
        if (p = strchr(str[i], '\n'))
            *p = '\0';   
    }  
    result = longestStrInAr(str, size, &length);
    printf("longest: %s \nlength: %d\n", result, length);         
    return 0;
}

char *longestStrInAr(char str[N][40], int size, int *length) {
    char *p;
    for (int i = 0; i < size; i++) {
        int j = 0; int max = 0, *length = 0;
        while (str[i][j++] != '\0') {
            max++;
        }
        if (max > *length) {
            *length = max;
            p = str[i];
        }
    }
    return p;
}

The line

int j = 0; int max = 0, *length = 0;

is bad. A new pointer variable length is declared here and initialized to NULL , shadowing the argument length .
After that, this length ( NULL ) is dereferenced and it will cause Segmentation Fault.

To initialize what is pointed at by the argument length to zero, the line should be:

int j = 0, max = 0; *length = 0;

In function longestStrInAr , the code in the for loop is incorrect:

    int j = 0; int max = 0, *length = 0;

defines 3 local variables: j , max and length as a new pointer to int , initialized as a null pointer. This length variable has the same name as the function argument but is defined in the scope of the block that is the body of the for statement, hence it shadows the argument with the same name. This problem would have been diagnosed by the compiler if given a higher level of warnings ( gcc -Wall -Wextra -Wshadow , clang -Weverything ).

This is causing the segmentation fault: when you later dereference this pointer in if (max > *length) , you have undefined behavior as length is a null pointer.

You probably meant to just use the argument and initialize *length , and you should do this before the for loop. Note also that you should initialize p as p = str[0] for the pathological case where all strings are empty for which the posted code returns an uninitialized pointer. As a matter of fact, there is another special case to consider: if size is 0 , the function should return NULL .

There are some problems in the main function too: if size is greater than N , you read strings beyond the end of the array.

Here is a modified version:

#include <stdio.h>

#define N 20

char *longestStrInAr(char str[][40], int size, int *length);

int flush_input(void) {
    int c;
    while ((c = getchar()) != EOF && c != '\n')
        continue;
    return c;
}

int main() {
    int i, size, length;   
    char str[N][40];
    char *result;
    
    printf("Enter array size: \n");
    if (scanf("%d", &size) != 1 || size < 0 || size > N) {
        fprintf(stderr, "invalid input\n");
        return 1;
    }
    // read and discard the rest of the input line
    flush_input();
    for (i = 0; i < size; i++) {
        printf("Enter string %d: \n", i + 1);
        str[i][0] = '\0';
        scanf("%39[^\n]", str[i]);
        flush_input();
    }  
    result = longestStrInAr(str, size, &length);
    printf("longest: %s \nlength: %d\n",
           result ? result : "(null)", length);         
    return 0;
}

char *longestStrInAr(char str[][40], int size, int *length) {
    char *p = NULL;
    *length = 0;
    if (size > 0) {
        for (int i = 0; i < size; i++) {
            int j = 0;
            while (str[i][j] != '\0')
                j++;
            if (*length < j) {
                *length = j;
                p = str[i];
            }
        }
    }
    return p;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM