1
#include <stdio.h>

int strend(char *s, char *t);

int main()
{
    char a[] = "hello world";
    char b[] = "orld";
    int i  = strend(a,b);
    printf("%d",i);
    return 0;
}

/* Write the function strend(s,t), which returns 1 if the string t occurs at the end of the string s, and zero otherwise. */
int strend(char *s, char *t)
{
    char *se = s;
    char *te = t;

    while (*se)
        se++;
        
    while (*te)
        te++;
    
    while(se>=s&&te>=t){
        if (*se!=*te)
            return 0;
        se--;te--;// is this alright???
    }
    return ++te==t;
}

In this way the pointer goes before the array pointer, is there some cases where the array pointer is intialize to 0 and te-- causes underflow problems? How should i rewrite the code in this case?

11
  • 1
    I think this is legal in C/C++ to go one before/after the last valid index as long as you don't dereference the vale at that address. Language lawyer would know better. Commented May 1, 2024 at 15:17
  • 3
    @selbie One after - yes, one before is undefined I believe. See port70.net/~nsz/c/c11/n1570.html#6.5.6p8 Commented May 1, 2024 at 15:20
  • 6
    One after an array is OK — that address must exist (but you shouldn't read from or write to that location). One before an array is not OK. On segmented addressing systems, all hell can break loose. On many systems, you will get away with it, but it is not sanctioned by the standard. Commented May 1, 2024 at 15:20
  • 1
    OT: for readability I'd rather write (se >= s && te >= t) instead of (se>=s&&te>=t), or at least (se>=s && te>=t). Commented May 1, 2024 at 15:29
  • 1
    @JonathanLeffler your comment is practically and answer. Commented May 1, 2024 at 15:31

2 Answers 2

3

Transferring my comment into an answer.

Generating addresses one before or after an array

One after an array is OK — that address must exist (but you shouldn't read from or write to that location).

One before an array is not OK. On segmented addressing systems, all hell can break loose. On many systems, you will get away with it, but it is not sanctioned by the standard.

You can find information about this at various points in the C11 standard.

See §6.5.6 Additive operators:

For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.

When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i+n-th and i-n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.

When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. The size of the result is implementation-defined, and its type (a signed integer type) is ptrdiff_t defined in the <stddef.h> header. If the result is not representable in an object of that type, the behavior is undefined. In other words, if the expressions P and Q point to, respectively, the i-th and j-th elements of an array object, the expression (P)-(Q) has the value i-j provided the value fits in an object of type ptrdiff_t. Moreover, if the expression P points either to an element of an array object or one past the last element of an array object, and the expression Q points to the last element of the same array object, the expression ((Q)+1)-(P) has the same value as ((Q)-(P))+1 and as -((P)-((Q)+1)), and has the value zero if the expression P points one past the last element of the array object, even though the expression (Q)+1 does not point to an element of the array object.106)

106) Another way to approach pointer arithmetic is first to convert the pointer(s) to character pointer(s): In this scheme the integer expression added to or subtracted from the converted pointer is first multiplied by the size of the object originally pointed to, and the resulting pointer is converted back to the original type. For pointer subtraction, the result of the difference between the character pointers is similarly divided by the size of the object originally pointed to. When viewed in this way, an implementation need only provide one extra byte (which may overlap another object in the program) just after the end of the object in order to satisfy the "one past the last element" requirements.

Also §6.5.8 Relational operators ¶5:

When two pointers are compared, the result depends on the relative locations in the address space of the objects pointed to. If two pointers to object types both point to the same object, or both point one past the last element of the same array object, they compare equal. If the objects pointed to are members of the same aggregate object, pointers to structure members declared later compare greater than pointers to members declared earlier in the structure, and pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values. All pointers to members of the same union object compare equal. If the expression P points to an element of an array object and the expression Q points to the last element of the same array object, the pointer expression Q+1 compares greater than P. In all other cases, the behavior is undefined.

Also §6.5.9 Equality operators¶6:

Two pointers compare equal if and only if both are null pointers, both are pointers to the same object (including a pointer to an object and a subobject at its beginning) or function, both are pointers to one past the last element of the same array object, or one is a pointer to one past the end of one array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space.109)

109) Two objects may be adjacent in memory because they are adjacent elements of a larger array or adjacent members of a structure with no padding between them, or because the implementation chose to place them so, even though they are unrelated. If prior invalid pointer operations (such as accesses outside array bounds) produced undefined behavior, subsequent comparisons also produce undefined behavior.

Fixing strend()

You should probably use strlen() to determine the lengths of the strings. If t is longer than s, it isn't at the end of s so return failure, 0. Otherwise, use string compare (strcmp()) on s + strlen(s) - strlen(t) and t to determine whether the string occurs. If you're not allowed to use the functions, write the code so that you can see where those functions would appear. There's no need to index off the start of an array.

int strend(const char *s, const char *t)
{
    size_t slen = strlen(s);
    size_t tlen = strlen(t);

    if (tlen <= slen && strcmp(s + slen - tlen, t) == 0)
        return 1;
    return 0;
}

Untested code — but there's a moderate chance it's OK.

Sign up to request clarification or add additional context in comments.

2 Comments

"Accessing elements" is a poor choice of wording for the leading headline. As I know you know, accessing such elements is not, in general, valid. On the other hand, computing the address one past the end of an array is always allowed, provided, in the general case, that you do not use the computed result to access an object.
Agreed — changed (I hope adequately fixed). Alternatives to "generating" include "calculating", "producing", and "creating"…
0

The following seems equivalent with what you have, but uses index values instead of pointer math. Avoids the technicalities of assigning a pointer to the -1 position.

int strend(char *s, char *t)
{
    int sIndex = 0;
    int tIndex = 0;

    while (s[sIndex]) {
        sIndex++;
    }
        
    while (t[tIndex]) {
        tIndex++;
    }

   
    while(sIndex >= 0 && tIndex >= 0) {
        if (s[sIndex] != t[tIndex]) {
            return 0;
        }
        sIndex--;
        tIndex--;
    }
    
    tIndex++;
    return (tIndex == 0);
}

And the above can be simplified even further to exactly what Jonathan has in his answer.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.