Laboratory: Simple String Manipulation

Gábor Horváth / Zsolt Kohári · 2020.10.29.

Low level string handling.

We will need pointers to solve the problems of this lab. Either because of indirect parameters, or because of arrays.

When passing an array as a function parameter, its memory address is passed just like if &t[0] was passed. For this reason usually the size of the array must be passed, too. Except for the strings, where the content determines the end of the array (terminating zero), so we almost never pass the size of a string. Make thoughtful decision at each problem whether to pass the size or not!

Preparation for lab:

  • Review lecture topics on pointers and strings.

1. Vertically

Write a program that asks the user to enter a word, stores it in a string, and prints it letter by letter vertically. For example if you give „Word”, the result should be:

W
o
r
d

You can assume that the word is never longer than 99 characters.

Hint

The easiest way to read a word from the keyboard is to use the scanf function. It will read the letters till the first white space and put them to the array passed to it, including the terminating zero. Make sure that the array passed to scanf is long enough to accomodate the longest expected word.

Solution

#include <stdio.h>

int main(void) {
    char name[100];

    printf("Your first name:\n");
    scanf("%s", name);

    for (int i = 0; name[i] != '\0'; ++i)
        printf("%c\n", name[i]);

    return 0;
}

2. Trimmer

It is a common task to remove leading and trailing spaces from a string. This function is often called trim().

Write a function that removes the spaces from the beginning and from the end of a string (other spaces must stay)! For example if the original string is "  Hi, what's up?   ", then the new string should be "Hi, what's up?". The function should take two parameters: a source array (containing the original string) and a destination array (to put the trimmed string into). You can assume that the destination array is long enough for the resulting string.

Do we need to pass the size of the array? Why?

Hint

1) First find (and remember) the first non-space character from the beginning of the string, 2) then find the end of the string, 3) and starting from there find the first non-space character backwards (the last one in the string). These two positions identify the segment of the string to copy. After copying into destination, do not forget to terminate the destination string.

Write a short program, too, that calls this function and demonstrates that it operates correctly!

Modify your function to allocate space for the trimmed string! What is the difference in calling? Why the resulted string still "alive" outside the function? (Do not forget to erase the memory allocation!)

Solution

#include <stdio.h>

void trim(char *source, char *dest) {
    int begin = 0, end = 0;

    /* Jump spaces at the beginning */
    while (source[begin] != '\0' && source[begin] == ' ')
        begin++;
    /* Where is the end od the string? Then go back and cut the trailing spaces */
    while (source[end] != '\0')
        end++;
    end--;
    while (end >= 0 && source[end] == ' ')
        end--;
    /* Copy to the beginning and close */
    int i;
    for (i = 0; i <= end-begin; i++)
        dest[i] = source[begin+i];
    dest[i] = '\0';
}
int main(void) {
    char s1[100] = "      Hey what's up?   ";
    char s2[100];

    trim(s1, s2);
    printf("[%s] [%s]\n", s1, s2);

    return 0;
}

3. Values backwards

Write a program, that first asks the user the number of real values to read; then it reads the values into a dynamically allocated array. At the end the program should print the elements of the array backwards, and release the allocated memory!

Hint

To store arbitrary many values – not limited by neither the size of a static array nor the size of the stack –, dynamic memory handling is needed. Remember the lecture: malloc() allocates dynamic memory returning the starting address of the block. It can be casted to any type, depending on the type of elements we would like to store in the array. When we do not need the array anymore calling the free() function will release the allocated dynamic memory. Allocating the array must obviously be preceeded by reading the number of values.

Solution

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

int main(void) {
    int cnt;
    printf("How many numbers?\n");
    scanf("%d", &cnt);

    double *numbers = (double*) malloc(sizeof(double) * cnt); // !
    if (numbers == NULL) {
        printf("Memory allocation failed.\n");
        return 1;
    }

    printf("Enter %d numbers:\n", cnt);
    for (int i = 0; i < cnt; ++i) {
        scanf("%lf", &numbers[i]);                           // !
    }

    for (int i = cnt-1; i >= 0; --i) {
        printf("%g\n", numbers[i]);
    }

    free(numbers);                                           // !

    return 0;
}