1

だから私は今Cを学ぼうとしています、そして私がクリアしたいいくつかの基本的な構造体の質問があります:

基本的に、すべてはこのコードスニペットを中心にしています。

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

#define MAX_NAME_LEN 127

typedef struct {
    char name[MAX_NAME_LEN + 1];
    unsigned long sid;
} Student;

/* return the name of student s */
const char* getName (const Student* s) { // the parameter 's' is a pointer to a Student struct
    return s->name; // returns the 'name' member of a Student struct
}

/* set the name of student s
If name is too long, cut off characters after the maximum number of characters allowed.
*/
void setName(Student* s, const char* name) { // 's' is a pointer to a Student struct |     'name' is a pointer to the first element of a char array (repres. a string)
    char temp;
int i;
for (i = 0, temp = &name; temp != '\0'; temp++, i++) {
    *((s->name) + i) = temp;
}

/* return the SID of student s */
unsigned long getStudentID(const Student* s) { // 's' is a pointer to a Student struct
    return s->sid;
}

/* set the SID of student s */
void setStudentID(Student* s, unsigned long sid) { // 's' is a pointer to a Student struct | 'sid' is a 'long' representing the desired SID
    s->sid = sid;
}

ポインターの理解を固めるために、コードをコメントアップしました。それらがすべて正確であることを願っています。

また、別の方法があります。

Student* makeAndrew(void) {
    Student s;
    setName(&s, "Andrew");
    setStudentID(&s, 12345678);
    return &s;
}

これは何らかの形で間違っていると確信しています...また、setNameが正しく実装されていないと思います。

ポインタはありますか?(しゃれは意図されていません)

4

4 に答える 4

3

これは非常に間違っています。使用しないことを主張する場合は、strcpy次のようにします(テストされていません)

int iStringLength = strlen(name);
for (i = 0; i < iStringLength; i++) {
    s->name[i] = name[i];
}

ただし、長さが配列サイズより長くないことを確認してください。

これも間違い

Student* makeAndrew(void) {
   Student s;
   setName(&s, "Andrew");
   setStudentID(&s, 12345678);
   return &s; 
}

s関数が終了するとオブジェクトが破棄されるため、関数スコープに対してローカルですが、オブジェクトへのポインターを返します。したがって、このポインターを使用して構造体にアクセスしようとすると、インスタンスが存在しなくなるため無効になります。これを行いたい場合は、 を使用して動的に割り当てる必要がありますmalloc。または、ポインターをまったく返さず、 @Andrew の代替オプションを使用します。

于 2012-09-09T10:52:53.710 に答える
2

「別のメソッド」では、ローカルで宣言してStudent sいます。これにより、スペースが (通常はスタック上で) 動的に割り当てられ、完了時にそのアドレスが返されます。

ただし、そのスタック領域は戻り時に解放されるため、データが破損していないという保証はありません。実際、そうなる可能性が高いです。

メソッドの呼び出しで宣言Student sし、ポインターを makeAndrew に渡します。

void makeAndrew(Student *s) {
    setName( s, "Andrew");
    setStudentID( s, 12345678);
}


...

Student s;
makeAndrew( &s );

...
于 2012-09-09T10:52:42.523 に答える
0

関数makeAndrewはローカル変数へのポインターを返します。スコープが終了する前にのみ有効であるため、関数が終了するとすぐに、メモリが上書きされるとすぐに変更されます。つまり、ほぼ瞬時に変更されます。動的に割り当てる必要があります ( を使用するStudent *s = new Student;か、純粋な C に固執したい場合はを使用し、Student *s = malloc (sizeof Student );メモリ リークを避けるために必要がなくなったら、関数の外で解放します。

または、アンドリューが提案したように実行すると、エラーが発生しにくくなります。

于 2012-09-09T10:56:40.783 に答える
0

makeAndrew() 関数を変更して、一時変数へのポインタを返すことに関するエラーを修正するために、構造体へのポインタではなく構造体を返すだけにします。

Student makeAndrew(void) 
{
    Student s;
    setName(&s, "Andrew");
    setStudentID(&s, 12345678);
    return s;
}

Student aStudent = makeAndrew();

setName には、入力 c-string 内の別の文字を指すようにループ内でインクリメントしているため、char * である必要がある temp に関してエラーがあります。null終端も欠落していたと思います。コメントで言及したように、Student で name char 配列のオーバーフローをチェックする必要があります。

void setName(Student* s, const char* name) { // 's' is a pointer to a Student struct |     
    // 'name' is a pointer to the first element of a char array (repres. a string)
    const char *temp;
    int i;
    for (i = 0, temp = name; *temp != '\0' && i <= MAX_NAME_LEN; temp++, i++) 
    {
       *((s->name) + i) = *temp;
    }
    s->name[i] = '\0';
}

strncpy を使用して setName を簡略化できます。

void setName2(Student *s,const char *name)
{
    #include <string.h>
    strncpy(s->name, name,MAX_NAME_LEN);
    s->name[MAX_NAME_LEN] = '\0';
}
于 2012-09-09T14:58:13.843 に答える