我在这里对C有点新意,只想了解一些关于指针,指针指针和字符串的内容。这是我到目前为止写下的内容:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Return a pointer to an array of two strings. The first is the characters
of string s that are at even indices and the second is the characters from
s that are at odd indices */
char **parity_strings(const char *s) {
int len = strlen(s);
char **lst = malloc(sizeof(char*)*2);
for(int i=0; i<2; i++){
lst[i] = malloc(sizeof(char)*(len/2));
}
for(int i=0; i<len; i++){
if(i%2==0){
(*lst)[0]=s[i];
}else{
(*lst)[1]=s[i];
}
}
return lst;
}
int main(int argc, char **argv) {
char **r = parity_strings(argv[1]);
printf("%s %s %s", r[0], r[1], argv[1]);
return 0;
}
所以我想动态分配字符串数组和字符串本身所需的内存。我想知道我是否有正确的想法,希望返回类型为char**
的指针,指针指向char*
类型的两个指针,然后从那里访问每个char
的指针串。
我的输出不符合预期。我对C来说比较新,所以我还有很多东西要学习。
任何帮助都将不胜感激,谢谢。
答案 0 :(得分:2)
首先,确保为输出字符串中的空字节分配空间:
for(int i=0; i<2; i++){
/* Add an extra space for the \0 */
lst[i] = malloc(sizeof(char)*(len/2 + 1));
}
你的主要问题是奇怪的(*lst)[0]=s[i];
部分。这与数组在C中的工作方式有关。
数组的名称最好被认为是指向第0个元素的指针。因此,(*lst)
完全等同于编写lst[0]
。所以(*lst)[0]
只是用最新的偶数字重复覆盖第一个数组中的第一个字符,而(*lst)[1]
只是重复覆盖第一个数组的第二个字母。第二个数组从未被分配,因为它被分配,只包含随机数据。
for(int i=0; i<len; i++){
if(i%2==0){
/* i/2 makes sure every space gets filled,
remember / means integer division in C */
lst[0][i/2]=s[i];
}else{
lst[1][i/2]=s[i];
}
}
/* Null terminate both strings, to be safe */
/* terminate one early if the string was odd */
lst[0][len/2 -len%2] = '\0';
lst[1][len/2 ] = '\0';
return lst;
}
这个解决方案“快速而且肮脏” - 其中一个数组总是被双重终止,但是没关系,因为我们为它们分配了空间。
答案 1 :(得分:1)
char **split_odd_even (char *org) {
char **lst;
size_t len, idx;
lst = malloc(2 * sizeof *lst);
len = strlen (org);
lst[0] = malloc ((len+3)/2);
lst[1] = malloc ((len+3)/2);
for (idx =0; org[idx]; idx++){
lst[idx%2][idx/2] = org[idx];
}
lst[idx%2][idx/2] = 0;
idx++;
lst[idx%2][idx/2] = 0;
return lst;
}
答案 2 :(得分:1)
这似乎意味着以下功能,如下面的示范程序所示
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char ** parity_strings( const char *s )
{
size_t len = strlen( s );
char **lst = malloc( 2 * sizeof( char* ) );
lst[0] = ( char * )malloc( ( len + 1 ) / 2 + 1 );
lst[1] = ( char * )malloc( len / 2 + 1 );
size_t i = 0;
for ( ; i < len; i++ )
{
lst[i % 2][i / 2] = s[i];
}
lst[i % 2][i / 2] = '\0';
++i;
lst[i % 2][i / 2] = '\0';
return lst;
}
int main(void)
{
char *s[] = { "A", "AB", "ABC", "ABCD", "ABCDE" };
for ( size_t i = 0; i < sizeof( s ) / sizeof( *s ); i++ )
{
char **p = parity_strings( s[i] );
printf( "%s %s %s\n", p[0], p[1], s[i] );
free( p[0] );
free( p[1] );
free( p );
}
return 0;
}
它的输出是
A A
A B AB
AC B ABC
AC BD ABCD
ACE BD ABCDE
至于你的函数,那么你错误地计算了新数组的长度,忘了用终止零附加它们。此外,当不再需要字符串时,您应释放所有已分配的内存。
在这些陈述中
(*lst)[0]=s[i];
(*lst)[1]=s[i];
应至少写成
(*lst)[i / 2] = s[i];
(*( lst + 1 ))[i / 2] = s[i];
答案 3 :(得分:0)
这是一种更直接使用指针代替索引的惯用C方式:
char **parity_strings(const char *s) {
int len = strlen(s);
char **lst = malloc(sizeof(char*)*2);
for(i=0; i<2; i++){
lst[i] = malloc((len+3)/2); // reserve room for the terminating null
}
char *even = lst[0], *odd = lst[1]; // initializes pointers to even and odd parts
for(;;) { // tests inside the loop
*even++ = *s++; // directly processes s pointer!
if (*s == '\0') break;
*odd++ = *s++; // every second is odd...
if (*s == '\0') break;
}
*even = *odd = '\0'; // terminate the strings
return lst;
}
这种方式确实忘记了初始s
,但你不再需要它,而改变的只是一个本地指针。但由于必须返回lst
,因此代码永远不会更改lst[i]
,而是使用副本