这个问题与this topic非常接近,但我更喜欢这个解决方案提供的可行性和指示性澄清。
所以我有一个数据文件,我从中得到了很长的char数组。我想将这个字符串拆分成一个数组,在每种情况下,都是一个与该文件的一行对应的字符串
我看到了解决方案,但它们都使用有限的数组,因为我不知道每一行的长度,我真的需要动态地分配所有这些,但我找不到行的长度,因为strtok
没有t在每个字符串的末尾加上一个空字符\0
。
我现在得到的是这两个解决方案,但都不起作用:
int get_lines(char *file, char **lines) {
int nb_lines = 0;
char *token = strtok(file, "\n");
for(int i = 0; token != NULL; i++) {
token = strtok(NULL, "\n");
nb_lines = i;
}
nb_lines++;
lines = malloc((nb_lines + 1) * sizeof(char*));
lines[nb_lines] = '\0';
token = strtok(file, "\n");
for(int i = 0; token != NULL; i++) {
token = strtok(NULL, "\n");
int nb_char = 0;
for(int j = 0; token[j] != '\n'; j++) //This will cause SIGSEGV because strtok don't keep the '\n' at the end
nb_char = j;
nb_char++;
token[nb_char] = '\0'; //This cause SIGSEGV because token's allocation finish at [nb_char-1]
lines[i] = malloc(strlen(token) * sizeof(char)); //strlen cause SIGSEGV because I cannot place the '\0' at the end of token
printf("%s", token); //SIGSEGV because printf don't find the '\0'
lines[i] = token;
}
for(int i = 0; i < nb_lines; i++) {
printf("%s", lines[i]); //SIGSEGV
}
return nb_lines;
}
所以你可以在上面看到我想做什么以及为什么它不起作用的想法。
下面你会看到我做的另一个尝试,但我陷入了同一点:
int count_subtrings(char* string, char* separator) {
int nb_lines = 0;
char *token = strtok(string, separator);
for(int i = 0; token != NULL; i++) {
token = strtok(NULL, separator);
nb_lines = i;
}
return nb_lines + 1;
}
char** split_string(char* string, char* separator) {
char **sub_strings = malloc((count_subtrings(string, separator) + 1) * sizeof(char*));
for(int i = 0; string[i] != EOF; i++) {
//How to get the string[i] lenght to malloc them ?
}
}
我的文件非常大,行也可以这样,所以我不想malloc另一个大小为(strlen(file) + 1) * sizeof(char)
的表,以确保每一行都不会出现SIGSEGV而且我也发现这个解决方案相当肮脏,如果你们有其他想法,我会非常高兴。
(抱歉英语错误,我不是很好)
答案 0 :(得分:0)
使用strtok
的方法有两个缺点:首先,strtok
修改字符串,因此您只能传递原始字符串一次。其次,它会跳过空行,因为它会将nelines作为单个标记分隔符进行tretas ..(我不知道这对你来说是一个什么问题。)
您可以通过字符串单次传递来计算换行符。为行数组分配内存并进行第二次传递,在此处将字符串拆分为换行符:
char **splitlines(char *msg)
{
char **line;
char *prev = msg;
char *p = msg;
size_t count = 0;
size_t n;
while (*p) {
if (*p== '\n') count++;
p++;
}
line = malloc((count + 2) * sizeof(*line));
if (line == NULL) return NULL;
p = msg;
n = 0;
while (*p) {
if (*p == '\n') {
line[n++] = prev;
*p = '\0';
prev = p + 1;
}
p++;
}
if (*prev) line[n++] = prev;
line[n++] = NULL;
return line;
}
我已经分配了两个比新行数更多的行指针:一个用于最后一行不以换行结束而另一行在末尾放置NULL
哨兵的情况,以便你知道你在哪里结束。 (当然,您可以通过指向size_t
的指针返回实际行数。)
答案 1 :(得分:0)
以下提议的代码:
puts()
替换为printf()
现在是代码
#include <stdio.h> // getline(), perror(), fopen(), fclose()
#include <stdlib.h> // exit(), EXIT_FAILURE, realloc(), free()
int main( void )
{
FILE *fp = fopen( "untitled1.c", "r" );
if( !fp )
{
perror( "fopen for reading untitled1.c failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
char **lines = NULL;
size_t availableLines = 0;
size_t usedLines = 0;
char *line = NULL;
size_t lineLen = 0;
while( -1 != getline( &line, &lineLen, fp ) )
{
if( usedLines >= availableLines )
{
availableLines = (availableLines)? availableLines*2 : 1;
char **temp = realloc( lines, sizeof( char* ) * availableLines );
if( !temp )
{
perror( "realloc failed" );
free( lines );
fclose( fp );
exit( EXIT_FAILURE );
}
// implied else realloc successful
lines = temp;
}
lines[ usedLines ] = line;
usedLines++;
line = NULL;
lineLen = 0;
}
fclose( fp );
for( size_t i = 0; i<usedLines; i++ )
{
puts( lines[i] );
}
free( lines );
}
鉴于以上代码位于名为untitled1.c
的文件中,以下是输出。
#include <stdio.h> // getline(), perror(), fopen(), fclose()
#include <stdlib.h> // exit(), EXIT_FAILURE, realloc(), free()
int main( void )
{
FILE *fp = fopen( "untitled1.c", "r" );
if( !fp )
{
perror( "fopen for reading untitled1.c failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
char **lines = NULL;
size_t availableLines = 0;
size_t usedLines = 0;
char *line = NULL;
size_t lineLen = 0;
while( -1 != getline( &line, &lineLen, fp ) )
{
if( usedLines >= availableLines )
{
availableLines = (availableLines)? availableLines*2 : 1;
char **temp = realloc( lines, sizeof( char* ) * availableLines );
if( !temp )
{
perror( "realloc failed" );
free( lines );
fclose( fp );
exit( EXIT_FAILURE );
}
// implied else realloc successful
lines = temp;
}
lines[ usedLines ] = line;
usedLines++;
line = NULL;
lineLen = 0;
}
fclose( fp );
for( size_t i = 0; i<usedLines; i++ )
{
puts( lines[i] );
}
free( lines );
}