当我在笔记本电脑上运行时,我的代码有效,但是当我将其上传到hackerrank时,strtol出现错误

时间:2018-12-29 15:51:18

标签: c segmentation-fault

我正在从hackerrank那里遇到问题,这是问题所在:https://www.hackerrank.com/challenges/time-conversion/problem

tl; dr ,我们将像08:00:00 PM这样的时间转换为20:00:00

我从以下站点获得的str_split函数:Split string with delimiters in C

首先,这是我的完整代码:

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

char** str_split(char* a_str, const char a_delim)
{
    char** result    = 0;
    size_t count     = 0;
    char* tmp        = a_str;
    char* last_comma = 0;
    char delim[2];
    delim[0] = a_delim;
    delim[1] = 0;

    /* Count how many elements will be extracted. */
    while (*tmp)
    {
        if (a_delim == *tmp)
        {
            count++;
            last_comma = tmp;
        }
        tmp++;
    }

    /* Add space for trailing token. */
    count += last_comma < (a_str + strlen(a_str) - 1);

    /* Add space for terminating null string so caller
       knows where the list of returned strings ends. */
    count++;

    result = malloc(sizeof(char*) * count);

    if (result)
    {
        size_t idx  = 0;
        char* token = strtok(a_str, delim);

        while (token)
        {
            assert(idx < count);
            *(result + idx++) = strdup(token);
            token = strtok(0, delim);
        }
        assert(idx == count - 1);
        *(result + idx) = 0;
    }

    return result;
}


char* timeConverse(char* chr)
{
    int del1 = 8;
    int hour = 0;
    char str[3];
    char *result = malloc(10 * sizeof(str));
    char** tokens;

    char s[11];
    for (int i = 0; i < 11; i++)
    {
        s[i] = *(chr + i);
    }

    bool time_of_day = 0; // 0 is morning, 1 is afternoon

    tokens = str_split(s, ':');
    char *endptr;
    hour = strtol(*(tokens), &endptr, 10); // THE MAIN PROBLEM FOR SEGFAULT I THINK?
    free(tokens);

    // check if it is morning or afternoon
    if (s[8] == 'P')
        time_of_day = 1;

    // if it is afternoon add 12 to hour
    if (time_of_day)
    {
        hour += 12;
        //
        // remove the hour from the timer
        memmove(&s[0], &s[0 + 1], strlen(s) - 0);
        memmove(&s[0], &s[0 + 1], strlen(s) - 0);

        // turn hour from int to string and store that to str
        sprintf(str, "%d", hour);
    }

    // remove the last 2 element from the list (PM or AM)
    s[strlen(s) - 1] = 0;
    s[strlen(s) - 1] = 0;

    // add hour to the min and second and store to result
    sprintf(result, "%s%s", str, s);

    // print out the result
    return result;
    free(result);
}

int main(void)
{
    // this is just a test
    char* time = "07:05:45PM";
    char* result = timeConverse(time);
    printf("%s\n", result);
    return 0;
}

这是我关于黑客等级的代码:

#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* readline();

/*
 * Complete the timeConversion function below.
 */

/*
 * Please either make the string static or allocate on the heap. For example,
 * static char str[] = "hello world";
 * return str;
 *
 * OR
 *
 * char* str = "hello world";
 * return str;
 *
 */

char **str_split(char *a_str, const char a_delim) {
  char **result = 0;
  size_t count = 0;
  char *tmp = a_str;
  char *last_comma = 0;
  char delim[2];
  delim[0] = a_delim;
  delim[1] = 0;

  /* Count how many elements will be extracted. */
  while (*tmp) {
    if (a_delim == *tmp) {
      count++;
      last_comma = tmp;
    }
    tmp++;
  }

  /* Add space for trailing token. */
  count += last_comma < (a_str + strlen(a_str) - 1);

  /* Add space for terminating null string so caller
     knows where the list of returned strings ends. */
  count++;

  result = malloc(sizeof(char *) * count);

  if (result) {
    size_t idx = 0;
    char *token = strtok(a_str, delim);

    while (token) {
      assert(idx < count);
      *(result + idx++) = strdup(token);
      token = strtok(0, delim);
    }
    assert(idx == count - 1);
    *(result + idx) = 0;
  }

  return result;
}

char* timeConversion(char* chr) {
    /*
     * Write your code here.
     */
    int del1 = 8;
    int hour = 0;
    char str[3];
    char *result = malloc(10 * sizeof(str));
    char **tokens;

    char s[11];
    for (int i = 0; i < 11; i++) {
      s[i] = *(chr + i);
    }

    bool time_of_day = 0; // 0 is morning, 1 is afternoon

    tokens = str_split(s, ':');
    char *endptr;
    hour = strtol(*(tokens), &endptr, 10);
    free(tokens);

    // check if it is morning or afternoon
    if (s[8] == 'P')
      time_of_day = 1;

    // if it is afternoon add 12 to hour
    if (time_of_day) {
      hour += 12;
      //
      // remove the hour from the timer
      memmove(&s[0], &s[0 + 1], strlen(s) - 0);
      memmove(&s[0], &s[0 + 1], strlen(s) - 0);

      // turn hour from int to string and store that to str
      sprintf(str, "%d", hour);
    }

    // remove the last 2 element from the list (PM or AM)
    s[strlen(s) - 1] = 0;
    s[strlen(s) - 1] = 0;

    // add hour to the min and second and store to result
    sprintf(result, "%s%s", str, s);

    // print out the result
    return result;
    free(result);
}

int main()
{
    FILE* fptr = fopen(getenv("OUTPUT_PATH"), "w");

    char* s = readline();

    char* result = timeConversion(s);

    fprintf(fptr, "%s\n", result);

    fclose(fptr);

    return 0;
}

char* readline() {
    size_t alloc_length = 1024;
    size_t data_length = 0;
    char* data = malloc(alloc_length);

    while (true) {
        char* cursor = data + data_length;
        char* line = fgets(cursor, alloc_length - data_length, stdin);

        if (!line) { break; }

        data_length += strlen(cursor);

        if (data_length < alloc_length - 1 || data[data_length - 1] == '\n') { break; }

        size_t new_length = alloc_length << 1;
        data = realloc(data, new_length);

        if (!data) { break; }

        alloc_length = new_length;
    }

    if (data[data_length - 1] == '\n') {
        data[data_length - 1] = '\0';
    }

    data = realloc(data, data_length);

    return data;
}

它可以在我的PC上运行,但是当我在hackerrank上运行代码时,我将代码上传到timeConversion函数中,出现此错误:

 GDB trace:
Reading symbols from solution...done.
[New LWP 11121]
Core was generated by `solution'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  __GI_____strtol_l_internal (
    nptr=0x5847d900 <error: Cannot access memory at address 0x5847d900>, 
    endptr=0x7ffd1f2ba350, base=10, group=<optimized out>, 
    loc=0x7f60be451560 <_nl_global_locale>) at ../stdlib/strtol_l.c:292
#0  __GI_____strtol_l_internal (
    nptr=0x5847d900 <error: Cannot access memory at address 0x5847d900>, 
    endptr=0x7ffd1f2ba350, base=10, group=<optimized out>, 
    loc=0x7f60be451560 <_nl_global_locale>) at ../stdlib/strtol_l.c:292
#1  0x0000555a56bd0d43 in timeConversion (chr=<optimized out>)
    at solution.c:89
#2  0x0000555a56bd0a4e in main () at solution.c:126

我假设hackerrank编译器与我的编译器计算机不同。 我使用编译代码 gcc(Debian 8.2.0-12)8.2.0。

2 个答案:

答案 0 :(得分:2)

您的解决方案根本不需要str_split

只需替换

tokens = str_split(s, ';');
char *endptr;
hour = strtol(*(tokens), &endptr, 10); // THE MAIN PROBLEM FOR SEGFAULT I THINK?
free(tokens);

作者

char *endptr;
hour = strtol(s, &endptr, 10);

当然要删除char** tokens;,也要删除int del1 = 8;没用

答案 1 :(得分:1)

问题很可能是main()中的这一行:

char* time = "07:05:45PM";

更改为:

char time[] = "07:05:45PM";

在您的解决方案中,time是指向常量 constant 的指针,但是split_str()对其进行了修改。

该解决方案通常设计过度;以下将起作用:

char* timeConversion(char* s) 
{
    if (s[0] == '1' && s[1] == '2' ) 
    {
        if( s[8] == 'A' )
        {
            s[0] = '0' ;
            s[1] = '0' ;
        } 
    }
    else if( s[8] == 'P' ) 
    {
        s[0] += 1 ;
        s[1] += 2 ;
    }

    s[8] = 0 ;

    return s ;
}